DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux
  • Graceful Shutdown: Spring Framework vs Golang Web Services
  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4

Trending

  • How Clojure Shapes Teams and Products
  • APIs for Logistics Orchestration: Designing for Compliance, Exceptions, and Edge Cases
  • Building a Simple Todo App With Model Context Protocol (MCP)
  • Designing AI Multi-Agent Systems in Java
  1. DZone
  2. Coding
  3. Frameworks
  4. Transaction configuration with JPA and Spring 3.1

Transaction configuration with JPA and Spring 3.1

By 
Eugen Paraschiv user avatar
Eugen Paraschiv
·
Feb. 10, 12 · Interview
Likes (4)
Comment
Save
Tweet
Share
73.3K Views

Join the DZone community and get the full member experience.

Join For Free

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.

Configuring transactions with annotations

After the introduction of Java based configuration in Spring 3.0, configuring transactions was one of the last things to require XML. Spring 3.1 introduces the new @Enable annotations - @EnableTransactionManagement – which makes it possible to fully use Java for the configuration:

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
      ...
   }

   @Bean
   public PlatformTransactionManager transactionManager(){
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(
       entityManagerFactoryBean().getObject() );
      return transactionManager;
   }

}

However, if Java is not an option, here is the XML equivalent of this configuration:

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
   <property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />

For a full discussion and code samples on configuring Spring with JPA, check out a previous article of this series.

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.

The API layer transaction strategy

With the previous transaction configuration, the Service layer is the transaction owner – it is responsible with starting the transaction and it contains any potential rollback logic. This does however have one downside: a Service write method can invoke another Service write method; because both may contain rollback logic, the transaction owner may not have full control over the rollback logic in some circumstances. For this reason care must be taken if the transaction owner resubmits the transaction or takes corrective action – in these cases the service logic may need to be refactored to avoid this scenario.

The API layer strategy is meant to address this shortcoming by making the Controller layer the transaction owner and working with the assumption that a public Controller method shouldn’t invoke another in any scenario. With this transaction strategy, the DAO and Service transactional semantics remain the same as before; the Controller layer however will use the REQUIRES_NEW propagation to ensure that it invokes the underlying Service layer in a transactional context.

@Transactional( propagation = Propagation.REQUIRES_NEW )
public class Controller{
   ...
}
@Transactional( propagation = Propagation.MANDATORY )
public class Service{
   ...
}
@Transactional( propagation = Propagation.MANDATORY )
public class DAO{
   ...
}

Spring Testing support for Transactions

The TestContext framework provides transaction support Spring enabled tests via the PlatformTransactionManager bean in the application context and the @Transactional annotation.

Spring also support various test specific annotations which, used in conjunction with the TestContext framework allow for full control over the transaction configuration: @TransactionConfiguration, @Rollback and @BeforeTransaction/@AfterTransaction.

A common usage of the framework and a common requirement of an integration test is to leave the database unchanged after the test method is finished. This can be done by annotating the test class with:

@TransactionConfiguration( defaultRollback = true )
@Transactional
public class TransactionalIntegrationTest{
   ...
}

Also, note that because Spring uses proxies at runtime to manage transactions, the test class must not be final if it’s annotated with @Transactional.

Potential Pitfalls

Changing the Isolation level

One of the major pitfalls when configuring Spring to work with JPA is that changing the isolation of the transaction semantics will not work – JPA does not support custom isolation levels. This is a limitation of JPA, not Spring; nevertheless changing the @Transactionalisolation property will result in:

org.springframework.transaction.InvalidIsolationLevelException: Standard JPA does not support custom isolation levels – use a special JpaDialect for your JPA implementation

Read Only Transactions

The readOnly flag usually generates confusion, especially when working with JPA; from the javadoc:

This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.

The fact is that it cannot be guaranteed that an insert or update will not occur when the readOnly flag is set – its behavior is vendor dependent whereas JPA is vendor agnostic.

It is also important to understand that the readOnly flag is only relevant inside a transaction; if an operation occurs outside of a transactional context, the flag is simply ignored. A simple example of that would calling a method annotated with:

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

from a non-transactional context – a transaction will not be created and the readOnly flag will be ignored.

Transaction Logging

Transactional related issues can also be better understood by fine-tuning logging in the transactional packages; the relevant package in Spring is “org.springframework.transaction”, which should be configured with a logging level of TRACE. 

Configuring transactions with AOP

In addition to annotations, the declarative transactional configuration can of course make use of the aspect-oriented programming support in Spring. As this is not meant to be an exhaustive guide to all the possible ways to configure transactions in Spring, check out the reference for a in depth discussion on using AOP to configure transactions.

This is a quick starting point to configuring transactions with AOP:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

   <tx:advice id="txAdvice" transaction-manager="txManager">
      <tx:attributes>
         <tx:method name="get*" read-only="true" />
         <tx:method name="*" />
      </tx:attributes>
   </tx:advice>
   <aop:config>
      <aop:pointcut id="serviceOperation" expression="execution(* org.rest.service.*.*(..))" />
      <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
   </aop:config>

</beans>

Conclusion

This article covered the configuration of the transactional strategies with Spring 3.1 and JPA, using both XML and Java based configuration. Two transaction strategies were discussed, focusing on different ways to manage transaction propagation between the layers of an application. The Spring support for transactional testing as well as some common JPA pitfalls were also discussed. You can check out the full implementation in the github project.

From the originalTransaction configuration with JPA and Spring 3.1 of the Persistence with Spring series

Spring Framework

Opinions expressed by DZone contributors are their own.

Related

  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux
  • Graceful Shutdown: Spring Framework vs Golang Web Services
  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!