In this tutorial, we will see Spring transaction management example using spring boot. First, we will see some basics about Spring Transaction Management then we will see a complete example.
We will see how to use @Transactional annotation, what will happen if we don’t use @Transaction annotation. We will also cover what are attributes defined for @Transactional annotation and what it does.
Table of Contents
Spring Transaction management basics.
The transaction can be defined with ACID properties.
Atomicity – All success or none.
Consistency – Database constraints should not be violated.
Isolation – One transaction should not affect another one.
Durability – It should in Database after commit.
Different ways of transaction management in Spring.
Three are two ways of define Trasaction management.
Programmatic transaction management.
Declarative transaction management.
Programmatic transaction management – Here we need to write some extra code for transaction management. When we say some extra code what does it mean? We need to take care of –
Creating Transaction reference.
Begin transaction.
Commit or rollback of the transaction.
Let’s see sample code.
Transaction transactionRef = entityManager.getTransaction() try { transactionRef.begin(); // business logic transactionRef .commit(); } catch(Exception e) { transactionRef.rollback(); e.printStackTrace(); }
Declarative transaction management – No need to write extra code for getting a transaction, we can use annotations or XML-based approach to manage the transactions and we can avoid unnecessary code. If we use annotation based approach we can use @Transactional and if we use the XML-based approach we need to configure DataSourceTransactionManager or any other transaction manager in XML as a bean. In this article and the next upcoming article, we will see the annotation based approach.
Sample code for annotation based declarative Spring transaction management.
@Transactional public Book findOneString objectId) { return repository.findOne(objectId); }
Sample code for XML-based declarative Spring transaction management.
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
We have seen basics about Spring transaction management example using spring boot.
Understanding Spring @Transactional annotation with example.
Till now we have seen ACID properties and different approaches to implement Spring transaction management. Now we will see how to implement declarative transaction management using annotation.
@Transactional is the key annotation that is responsible for declarative spring transaction management. Apart from this annotation, we use @EnableTransactionManagement.
Let’s see what is the advantage of using @Transactional annotation what happens if we don’t use @Transactional annotation. We will also see how to use @Transactional annotation.
@Transactional annotation used with class, interface or method.
Let’s see a small code snippet which would explain the effect of @Transactional annotation.
Consider you have class BookServiceImpl.java where you have logic to save Book entity.
@Service("bookServiceImpl") public class BookServiceImpl implements BookService{ @Autowired private BookRepository bookRepository; public Book saveBook(Book book) { Book book1 = bookRepository.save(book); int a = 10/0; System.out.println(a); return book1; } }
Observe the saveBook()
method. In the above code snippet line number 9 will throw ArithmeticException but before that bookRepository.save(book)
will get exected. Now the question comes would we have records in the database or not? In the above scenario even we have an exception in our code, we would have a record in Database.
That we might don’t want this to happen. If we have something wrong with our code, data should not persist in the database. Now just modify the code snippet as below, use @Transactional annotation with saveBook()
method.
@Service("bookServiceImpl") public class BookServiceImpl implements BookService{ @Autowired private BookRepository bookRepository; @Transactional public Book saveBook(Book book) { Book book1 = bookRepository.save(book); int a = 10/0; System.out.println(a); return book1; } }
Since we are using @Transactional annotation with saveBook()
method and we have ArithmeticException at code int a = 10/0
, our transaction will get rollbacked and we will not have any record in the database.
This is an example that explains what is the benefit of @Transactional annotation. Although @Transactional annotation does a lot of other stuff which we will cover later in separate tutorials.
Understanding Spring @Transactional Attributes.
So far we have seen effect of using @Transactional annotation. Let’s see what properties have been defined inside @Transactional annotation. We have different properties/attributes with @Transactional annotation so that we can have more control over our transaction. When we say more control over the transaction, what does it mean?
The @Transactional annotation has a different attribute and corresponding value. We can use those attributes and customized our transactions. For example, if we use @Transactional(readOnly=true) with the method, we will not able to update records. We use @Transactinal(readOnly = true) if our method performs an only search or retrieve operation. Similarly, we have @Transactinal(timeout = 100), which means if any transaction doesn’t complete in 100 seconds then it will throw time out error(see an example here).
Let’s see the possible attributes of @Transactional annotation.
@Transactional(isolation = Isolation.DEFAULT,
propagation=Propagation.REQUIRES_NEW,
readOnly=true,
noRollbackFor =ArithmeticException.class,
timeout = 30000,
value="txManager2",
rollbackFor = { Exception.class },
rollbackForClassName = {"Exception"},
noRollbackForClassName={"Exception"})
So here we have a sample code which elaborates what are the possible attributes for @Transactional. Another point here isolation and propagation attribute has different values. Now it seems a little bit tricky. Yes until unless we are not sure about attributes names and possible values(and what it does exactly, it is not easy to implement in real time development).
We will cover more points about Spring transaction management example using spring boot.
Let’s see all attributes/properties one by one.
Propagation – propagation can have different possible value as below.
Propagation.REQUIRED – Support a current transaction, create a new one if none exists.
Propagation.REQUIRES_NEW – Always create a new transaction and suspend the current transaction if already exist.
Propagation.MANDATORY – Support a current transaction, throw an exception if none exists.
Propagation.NESTED – Execute within a nested transaction if a current transaction exists.
Propagation.NEVER – Execute non-transactionally, throw an exception if a transaction exists.
Propagation.NOT_SUPPORTED – Execute non-transactionally, suspend the current transaction if one exists.
Propagation.SUPPORTS – Support a current transaction, execute non-transactionally if none exists.
Propagation.REQUIRED and Propagation.REQUIRES_NEW is frequently used in real-time development. See an example here.
Note – Default Propagation value is Propagation.REQUIRED
Isolation – isolation can have different possible value as below.
Isolation.READ_UNCOMMITTED – It allows dirty reads, non-repeatable reads, and phantom reads.
Isolation.READ_COMMITTED – Dirty reads are prevented, allows non-repeatable and phantom reads.
Isolation.REPEATABLE_READ – Dirty reads and non-repeatable prevented, phantom reads allowed.
Isolation.SERIALIZABLE – Dirty reads, non-repeatable reads, and phantom reads are prevented.
Note – Default isolation value is Isolation.DEFAULT.
rollbackFor – We can define zero, one or multiple exceptions for which we want our transaction to be rollbacked. We have a separate post where we can find more details.
@Transactional(rollbackFor = {RuntimeException.class})
noRollbackFor – We can define zero, one or multiple exceptions for which we don’t want our transaction to be rollbacked. We have a separate post where we can find more details.
@Transactional(noRollbackFor = {RuntimeException.class})
rollbackForClassName – We can define zero, one or multiple exceptions as String for which we want our transaction to be rollbacked. We have a separate post where we can find more details.
@Transactional(rollbackForClassName = {“NullPointerException”})
noRollbackForClassName – We can define zero, one or multiple exceptions as String for which we don’t want our transaction to be rollbacked. We have a separate post where we can find more details.
@Transactional(noRollbackForClassName = {“NullPointerException”})
readOnly – Its value can be true or false. Go through this post for more details.
@Transactional(readOnly = false)
Spring Transaction Management example using spring boot and Oracle.
Prerequisites.
- JDK 1.8
- Oracle 10g
- Eclipse
- maven
- postman
We will use the spring boot library (will provide dependency in pom.xml) to make sure all necessary jar/library is easily available for our application. Spring boot will take care of all jar. Let’ s start.
Create maven project, Don’t forget to check ‘Create a simple project (skip)’click on next. Fill all details(GroupId – restcontrollerexample, ArtifactId – restcontrollerexample and name – restcontrollerexample) and click on finish. Keep packaging as the jar.
Modify the pom.xml with below code.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springtransactionexample</groupId> <artifactId>springtransactionexample</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springtransactionexample</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.0</version> </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <start-class>com.springtransaction.springtransaction.SpringMainExample</start-class> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.springtransaction.springtransaction.SpringMainExample</mainClass> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <fork>true</fork> <executable>C:\Program Files\Java\jdk1.8.0_131\bin\javac.exe</executable> </configuration> </plugin> </plugins> </build> </project>
Note – In pom.xml we have defined javac.exe path in configuration tag. You need to change accordingly i.e where you have installed JDK.
Let maven download all necessary jar. Once it is done we will able to see the maven dependency folder which contains different jar files.
We can start writing our controller classes, ServiceImpl and Repository. The directory structure of the application.

Define main class SpringMainExample.java
SpringMainExample.java
package com.springtransaction.springtransaction; import org.hibernate.SessionFactory; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import com.springtransaction.entity.Book; import com.springtransaction.service.BookService; @SpringBootApplication(scanBasePackages={"com.springtransaction"}) @EntityScan("com.springtransaction.*") public class SpringMainExample { public static void main(final String[] args) { final ConfigurableApplicationContext configurableApplicationContext = SpringApplication .run(SpringMainExample.class, args); } @Bean public SessionFactory sessionFactory(final HibernateEntityManagerFactory hemf) { return hemf.getSessionFactory(); } }
Define entity class i.e Book.java
Book.java
package com.springtransaction.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "book") public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int bookId; @Column(name="book_name") private String bookName; @Column(name="auther_name") private String autherName; public String getAutherName() { return autherName; } public void setAutherName(String autherName) { this.autherName = autherName; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } @Column(name="price") private int price; public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } }
Define repository interface extending CrudRepository.
BookRepository.java
package com.springtransaction.repository; import java.io.Serializable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.springtransaction.entity.Book; @Repository public interface BookRepository extends CrudRepository<Book,Serializable> { public Book findByBookId(int bookId); }
Define service interface i.e BookService.java
BookService.java
package com.springtransaction.service; import org.springframework.stereotype.Component; import com.springtransaction.entity.Book; @Component public interface BookService { public Book findByBookId(int bookId); public Book saveBook(Book book); }
Define service implementation class.
BookServiceImpl.java
package com.springtransaction.serviceimpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.springtransaction.entity.Book; import com.springtransaction.repository.BookRepository; import com.springtransaction.service.BookService; @Service("bookServiceImpl") public class BookServiceImpl implements BookService{ @Autowired private BookRepository bookRepository; public Book findByBookId(int bookId) { Book book = bookRepository.findByBookId(bookId); return book; } @Transactional public Book saveBook(Book book) { Book book1 = bookRepository.save(book); return book1; } }
Define the controller class or endpoint.
BookController.java
package com.springtransaction.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.springtransaction.entity.Book; import com.springtransaction.service.BookService; @RestController @RequestMapping("/book") public class BookController { @Autowired private BookService bookService; @RequestMapping(value = "/getBook",method = RequestMethod.GET) @ResponseBody public Book getBookDetails(int bookId) { Book bookResponse = bookService.findByBookId(bookId); return bookResponse; } @RequestMapping(value = "/savebook",method = RequestMethod.POST) @ResponseBody public Book saveBook(@RequestBody Book book) { Book bookResponse = bookService.saveBook(book); return bookResponse; } }
Define JpaConfig class.
package com.springtransaction.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Configuration @EnableJpaRepositories(basePackages = "com.springtransaction.repository") public class JpaConfig { }
Step 13 – Define application.properties file
application.properties
# Connection url for the database spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE spring.datasource.username=SYSTEM spring.datasource.password=oracle1 spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.testWhileIdle = true spring.datasource.validationQuery = SELECT 1 # Show or not log for each sql query spring.jpa.show-sql = true spring.jpa.hibernate.ddl-auto =update spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect server.port = 9091 useBuiltinConverters: true mapNulls: true logging.level.org.springframework.transaction.interceptor=TRACE
First, we will save one book record using postman.

Now we have one record in DB. Let’s perform get operation

Although we have already discussed, just for reminding In the above example in BookServiceImpl.java, we are using @Transactional annotation with saveBook() method. If we don’t use @Transactional annotation it will work fine we will have a record in DB. But if we modify the BookServiceImpl.java something like below, then we would not have any record in the database. Our transaction will get rollbacked because of ArithmeticException
@Transactional public Book saveBook(Book book) { Book book1 = bookRepository.save(book); int a = 10/0; System.out.println(a); return book1; }
Note – It can be ArithmeticException, NullPointerException or any RuntimeException.
Tha’s all about Spring transaction management example using spring boot.
You may like.
- @Transactional REQUIRED vs REQUIRES_NEW example in spring boot.
- @Transactional rollbackFor example using spring boot.
- @Transactional noRollbackFor example using spring boot.
- @Transactional readonly true example in spring boot.
- @Transactional noRollbackForClassName example using spring boot.
- @Transactional rollbackForClassName example using spring boot.
- @Transactional timeout Using Spring Boot.
Spring Data JPA tutorials.
- Spring Data JPA greater than Example
- Spring Data JPA less than Example
- Spring Data JPA IsNull Example Using Spring Boot
- Spring Data findById() Vs getOne()
- Spring Data JPA CrudRepository findById()
- Spring Data JPA JpaRepository getOne()
- Spring Data CrudRepository saveAll() and findAll().
- Spring Data CrudRepository existsById()
- Spring Data JPA delete() vs deleteInBatch()
- Spring Data JPA deleteAll() Vs deleteAllInBatch()
- Spring Data JPA JpaRepository deleteAllInBatch()
- Spring Data JPA deleteInBatch() Example
- Spring Data JPA JpaRepository saveAndFlush() Example
- Spring Data JPA CrudRepository count() Example
- Spring Data JPA CrudRepository delete() and deleteAll()
- Spring Data JPA CrudRepository deleteById() Example
- CrudRepository findAllById() Example Using Spring Boot
- Spring Data CrudRepository save() Method.
- Sorting in Spring Data JPA using Spring Boot.
- Spring Data JPA example using spring boot.
- Spring Data JPA and its benefit.
See Docs here.
Summary – We have seen Spring Transaction managment example using Spring Boot. We covered @Transactinal attributes as well as.
We have all points about Spring transaction management example using spring boot.