📜 ⬆️ ⬇️

Transactions in Spring

The article describes an example of working with transactions in the popular framework Spring. The article assumes that you are familiar with java and spring. Working code example can be downloaded from sf



There are two management strategies: program management (we write code manually) and declarative (we set up transaction boundaries in XML configurations). In addition, we can work with different types of transactions: local and distributed.
')
General information on the use of transactions is available in the Spring documentation, but many encounter problems when trying to put information into practice. The article contains a working example for a local and distributed transaction, using both strategies.


Shortly about transactions


By transaction, we mean a series of actions (not necessarily in the database), which are perceived by the system as a single package, i.e. or all actions are successful, or all are rolled back to their original positions.

Consider the classic example of transferring money from one account to another. Money transfer is our “package”, which contains two actions: it reduces the balance of account A and increases the balance of account B. It is obvious that we cannot reduce the first account, and fail to increase the second - in case of an error we must roll back both operations.

As we said earlier, there are two types of transactions - local and distributed. A local transaction works with one source, for example, one database; distributed uses a few - for example jms source and db.

If the mechanism of local transactions is simple, then a certain infrastructure is required for distributed ones. A distributed process requires a certain element that will synchronize the work of all sources. This item is a distributed transaction manager. Such managers are issued by a large number of companies, and they all require a certain study of the documentation.

But there is a much simpler way - to use any jEE server, since they contain pre-configured components. In our example, we will try to use JBoss 5.

For more information about the mechanisms of transactions I recommend to see wikipedia.

Environment


First, we need data sources: create two databases in mysql and call them Alfa and Beta. In alpha, we make two tables: alfa1 and alfa2; The table structures are the same and contain the id and name fields. Additionally, we add a unique index on the name column for alfa1. In the Beta database, create only one table with the same fields and a unique index.

Be sure to specify the engine for the tables - InnoDB, otherwise transactions will not work.
In the archive with an example there is a script for creating all the structures.

Use case


Our script contains two operations: each inserts data into one table. Since the alfa2 table does not contain an index, we can insert any number of duplicates. Duplicates in the remaining tables are not possible, and as a result, we should receive an error when re-inserting and rolling back the transaction.

Each example must be run twice: the first start will end normally and in both tables there will be new entries; restart will fail.

Local Transaction Example


Local transaction works with one base: Alfa. Connection to the database is described in the standard spring context, along with descriptions of the data access layer and the layer service. There are also hibernate configurations.
Data access object contains two methods for inserting data (alfa1 alfa2).
The layer service uses dao for immediate work.

For a start, let's try the program management method.
Create a context (programContext.xml) and declare all the bins: connection to the database, hibernate configuration, dao and service. All bins use dependency injection.
The most important bean for us is the transaction manager. We declare a standard class and use it in our service. In the Service an example of use is indicated - this is the only nuance.
We also do a class for running our structures, which initializes the context and calls our service layer. The first run is performed normally and we see the data in the tables alfa1 and alfa2. Restarting causes an error - since there is a unique index on alfa1, but a rollback will occur in the alfa2 table as well, which was necessary for us.
In this approach, we had to explicitly use the transaction manager, i.e. our code has become dependent on external libraries. We can avoid this by using a declarative approach to managing transactions.

We will create a new object in the service layer, in which there will be no transaction management code, and declare all the beans in the new context.
(declarativeContext.xml). Connections to the database, settings, transaction manager - all this is similar to the previous example. The only difference in the definition of Service, now it does not use the transaction manager.
But we still need the transactions ourselves, and we need to inform spring about this. In general, we need to declare two elements: what methods we want to put in the transaction, and which manager to use.
The rule for defining the method: execution (* service.DeclarativeTx. * (..)) - i.e. We choose all the methods of our service. And the next setting says that we will use the default manager.
Delete the data from the tables and run the example twice. As usual, the first run is performed normally, and the second ends with an error, along with the rollback of the entire transaction.

Distributed Transaction Example


Most applications have enough local transactions to succeed. But there are a number of applications that are forced to work with data distributed by many sources. In this case, distributed transactions are used to manage changes.
In general, everything works in the same way as normal transactions, except for the fact that we need to synchronize the work of all sources. It helps a separate subsystem: the manager of management of distributed transactions.
Managers are released by a large number of vendors as separate software products, i.e. we must download, install and configure the system. To do this, you will have to read the documentation and TP, but we will choose the path easier: modern jee application servers contain built-in, already configured managers.
We will use jboss 5, although you can use any other. Thanks to spring's flexibility not to make server-dependent changes.

Our goal: to create a web application with a single flow. The controller must invoke services to insert data into both databases. As usual, the first page display will be successful, and the second will cause an error with the rollback of the transaction.

The application deployment will take place in JBoss, which we have to pre-configure. At a minimum, we need access to both databases - we will create two files to configure datasources and copy them into server / default / deploy. The files themselves are available in the archive with an example. Perhaps you need to change the username and password, and, most importantly, do not forget to put the driver for myysql in the jdbc server lib.

The application itself is also in the archive. Let's take a closer look at it, instead of writing an analog from scratch.
The project contains jars: the most springs needed to support web, hibernate and so on.
The source code is generally similar to the previous examples: in the context there are two datasource configured via jndi. There are hibernate mapping, dao, serice layer. The declarative definition of transactions is also similar to the earlier example.
Pay attention to the definition of a distributed transaction manager. We said earlier: we must use some kind of external system for managing transactions. But we do not make any configurations, thanks to spring. When spring is initialized, the available manager will automatically be found via jndi - because it takes the standard jndi paths for all popular servers, and sequentially iterates over them.

Additionally, we create web flow using mvc. Our controller calls the service to work with databases.
As usual, the first launch (opening of the page) is successfully processed, if the page is reloaded - we get exception and rollback of the transaction.

To run web sample


Create both bases. Copy and unzip JBoss5. Edit the source definitions from the example and write them into server / default / deploy.
Package the application in xa.wat and copy the WAR in deploy.
Run JBoss (bin / run) and, if everything is in order, open:
localhost : 8080 / xa / testxa.do

Andrew Romanenco
andrew@romanenco.com
www.romanenco.com/springtx

You can download sample code from sf.net:

sourceforge.net/project/showfiles.php?group_id=220231&package_id=326183&release_id=689145

Source: https://habr.com/ru/post/62484/


All Articles