In the tutorial below I will focus on transactions management with Spring 3. For the sake of simplicity, we will create a standalone Java application – but the same logic can be used in J2EE application. We will create:
Entity objects (simple POJO) – the basic entities mapped to the relational database (via annotations).
DAO objects handling database (Hibernate) queries.
Business Object that will expose services around our data.
Main application to simply run our code. This is what will probably need to be replaced with your web application logic, if you are creating one.
Our application will be very simple – two main tables/objects: User and Email, with the many-to-many relationship between them. Let’s start with the SQL to create and populate database. I’m using MySQL but it should work on any other DB with the minimal changes:
Next, our entity objects. You can download a full source code, so I’m displaying here only the relevant parts of the code. Entity objects are simple POJOs but they contain annotations for Hibernate:
Our DAO objects will need a reference to SessionFactory – we will use a constructor to pass that object and let Spring do the job. Let’s define a getFirstEmail method in UserDao – suppose this is for finding only one, primary email for a user.
EmailDao is not even worth showing here – it simply extends AbstractDao. Now, our business logic finally. We will be coding to an interface, so we’ll create interface net.opensesam.bo.UserBo:
The methods are implemented by UserBoImpl. All of them are used from the Main class, so you can refer to the source code – let’s have a look at only one of them – public void complexTransaction(User user). This is to emulate a few-steps transaction:
If an exception is run in the middle of the method, Spring should rollback the transaction. Otherwise, the whole complexTransaction method should execute as one transaction.
All the magic happens in Spring configuration – beans.xml in my case:
We need to define transactionManager that will understand the persistence technology we are using – hence HibernateTransactionManager in this case. Transaction manager obviously needs a reference to SessionFactory. Every time our transactional method is run, Transaction Manager has to run as well and do all the work for us, like: opening connection if needed, starting transaction, rolling back / committing. This means we need some kind of proxy object, or a wrapper around UserBoImpl class. AOP comes in very handy here, as we can have that done declaratively, without any changes to the source code. First we define when our transaction management code should run by setting pointcut=”execution(* net.opensesam.bo.*.*(..))”. You may want to refer to Spring AOP tutorial for the very basics of AOP. Next, we define our advice (what should run) txAdvice that refers to the transaction manager we use. tx:attributes element contains additional information like: which methods should be transactional, which of them can be declared as read-only for possible optimizations and under what conditions should rollback be triggered. By default any unchecked exception will trigger rollback. The example above is very simple, basically any method from any class from net.opensesam.bo package will be treated as transactional.
The above works as expected – here is what I can see in MySQL log, when the exception is not thrown:
Compare it with what happens if when the exception is thrown:
The list of jar files used while working on the code: