This is the fifth of a series of articles about Persistence with Spring. This article will focus on the configuration of transactions with Spring 3.1 and JPA. For a step by step introduction about setting up the Spring context using Java based configuration and the basic Maven pom for the project, see this article.
The Persistence with Spring series:
- Part 1 – The Persistence Layer with Spring 3.1 and Hibernate
- Part 2 – Simplifying the Data Access Layer with Spring and Java Generics
- Part 3 – The Persistence Layer with Spring 3.1 and JPA
- Part 4 – The Persistence Layer with Spring Data JPA
- Part 5 – Transaction configuration with JPA and Spring 3.1
Spring and Transactions
Spring provides a consistent and comprehensive transaction abstraction over many supported environments. There are two distinct ways of configuring and using transactions – annotations and AOP – each with their own advantages. The reference should provide enough material on both the decision to use the Spring transaction programming model, as well as a in depth discussion of its architecture.
The @Transactional configuration
By default, @Transactional will set the propagation to REQUIRED, the readOnly flag to false, and the rollback only for unchecked exceptions. Also note that the isolation level is set to the database default; when using JPA, the isolation level is that of the underlying persistence provider. In the case of Hibernate, the isolation level of all transactions should be REPEATABLE_READ.
For the purpose of this discussion, the relevant application layers will be DAO, Service and Controller. These layers can of course vary from application to application, without changing the underlying principles discussed here.
The @Transactional semantics of the Service and DAO layers should both be configured with REQUIRED propagation and the readOnly flag set to true for the relevant methods. The Controller layer should contain no transaction logic.
Note that this is also the way the DAO implementation is configured in Spring Data. For a detailed analysis of the persistence layer with Spring data, see the previous article of this series.
Assuming a clean separation of layers, where the Controller layer will only invoke the Service layer, which in turn will only call the DAO, then the DAO layer will never be called in a non-transactional context. As such the DAO will never be the transaction owner, and a more strict transaction configuration should be used for it. In this situation, the transactional semantics should be MANDATORY propagation and no readOnly flag. The MANDATORY propagation will simply ensure that a transaction has already been started when the DAO layer is entered, double checking the stated assumption that the DAO is never the transaction owner. The readOnly flag is also not needed because it will be set by the transaction owner as well.