Home Java Transactions in Spring

Transactions in Spring

by admin

This article gives an example on how to work with transactions in the popular Spring framework. The article assumes that you are familiar with java and spring. A working example code can be downloaded from sf
There are two management strategies: program management (we write code manually) and declarative management (we configure transaction boundaries in XML configurations). In addition, we can work with different types of transactions: local and distributed.
General information on using transactions is available in the Spring documentation, but many encounter problems when trying to put the information into practice. This article contains a working example for local and distributed transactions, using both strategies.

Short on transactions

By a transaction we mean a series of actions (not necessarily in the database) that are perceived by the system as a single batch, i.e. either all actions succeed, or all roll back to their original positions.
Consider the classic example of transferring money from one account to another. A money transfer is our "package" which contains two actions: decreasing the balance of account A and increasing the balance of account B. Obviously, we cannot decrease the first account and fail to increase the second – in case of an error we must roll back both operations.
As we said before there are two types of transactions – local and distributed. A local transaction works with one source, e.g. one database; a distributed transaction uses several sources, e.g. jms source and database.
If the mechanism of local transactions is simple, the distributed ones require a certain infrastructure. A distributed process requires some element that will synchronize all sources. This element is a distributed transaction manager. Such managers are produced by a large number of companies, and all of them require some study of documentation.
But there is a much easier way which is to use any jEE server as they contain already configured components. In our example we will try to use JBoss 5.
For more information on transaction mechanisms, I recommend looking at wikipedia.

Environment

First, we will need data sources: we will create two databases in mysql and we will call them Alfa and Beta. In alpha, we will make two tables: alfa1 and alfa2; the structures of the tables are the same and contain id and name fields. Additionally we will add a unique index to the column name for alfa1. In the Beta base we will create only one table with the same fields and a unique index.
Make sure to specify InnoDB engine for the tables, otherwise transactions won’t work.
In the archive with the example there is a script to create all structures.

Use case

Our script contains two operations: each one inserts data into the same table. Since table alfa2 does not contain an index, we can insert any number of duplicates. Duplicates in the other tables are not possible, and as a consequence, we should get an error on reinsertion and rollback the transaction.
Each example has to be run twice: the first start will end normally and both tables will have new entries; a second run will end with an error.

Example of a local transaction

A local transaction works with a single database: Alfa. Connection to the base is described in the standard spring context, together with descriptions of the data access layer and service layer. Hibernate configurations are also described there.
The data access object contains two methods for inserting data (alfa1 alfa2).
The layer service uses dao for direct operation.
First, let’s try the software control method.
We create a context (programContext.xml) and declare all the bins: database connection, hibernate configuration, dao and service. All bins use dependency injection.
The most important bin for us is the transaction manager. We declare a standard class and use it in our service. The Service specifies an example of how to use it, that’s the only nuance.
We also make a class to run our structures that initializes the context and calls our layer service. The first run runs fine and we see data in tables alfa1 and alfa2. Running it again causes an error – since there is a unique index on alfa1, but the rollback will happen in table alfa2 as well, which is what we needed.
In this approach, we had to explicitly use a transaction manager, meaning our code became dependent on external libraries. We can avoid this by using a declarative approach to transaction management.
We will create a new object in the service layer that will not contain any transaction management code and declare all the bins in the new context
(declarativeContext.xml). Connections to the database, settings, transaction manager are all similar to the previous example. The only difference is in the Service definition, now it doesn’t use a transaction manager.
But we still need the transactions themselves and we have to inform spring about it. So we have to declare two elements: which methods we want to put in the transaction and which manager to use.
The rule to define the method : execution(* service.DeclarativeTx.*(.)) – That is, we select all the methods of our service. And the next setting says that we will use the default manager.
Wipe the data from the tables and run the example twice. As usual, the first run runs fine, but the second one ends with an error, along with a rollback of the whole transaction.

Example of a distributed transaction

Most applications have sufficient local transactions to work successfully. But there are some applications that have to deal with data distributed from many sources. In this case, distributed transactions are used for change management.
In general, everything works as usual transactions, except that we have to synchronize all sources. This is where a separate subsystem helps: the distributed transaction manager.
These managers are produced by most of the vendors as separate software, so we have to download, install and configure the system. You have to read the documentation and so on, but we will take an easier way: modern jee application servers have managers already configured.
We will use jboss 5 although you can use any other one. Due to the flexibility of spring, you don’t have to make server-dependent changes.
Our goal : To create a web application with a single flow. The controller should call services to insert data into both databases. As usual, the first page display will succeed and the second will cause an error with a transaction rollback.
The deplay of the application will be done in JBoss, which we have to configure beforehand. At a minimum we need access to both databases – create two files for configuring datasources and copy them to server/default/deploy. The files themselves are available in the example archive. Maybe you should change username and password, and most importantly, do not forget to put in lib server jdbc driver for myysql.
The application itself is also in the archive. Let’s take a closer look at it, instead of writing an analogue from scratch.
This project contains jags: the spring itself, which are necessary to support web, hibernate, etc.
The source code is pretty much the same as the previous examples: there are two datasources in the context, configured via jndi. Hibernate mapping, dao, serice layer are present. The declarative definition of transactions is also similar to the previous example.
Note the definition of the distributed transaction manager. Earlier we said : we must use some external system to manage transactions. But we don’t make any configurations, thanks to spring. On initialization, spring will automatically find an available manager through jndi – because it knows the standard jndi paths for all popular servers, and sequentially goes through them.
Additionally, we create a web flow using mvc. Our controller calls the database service.
As usual the first run is successful, if the page is reloaded we get an exception and the transaction is rolled back.

To run a web sample

Create both databases. Copy and unpack JBoss5. Edit the source definitions from the example and write them to server/default/deploy.
Package the application in xa.wat and copy the WAR to deploy.
Run JBoss (bin/run) and if everything is OK, 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=220231package_id=326183release_id=689145

You may also like