Search code examples
spring-boothibernatejpaspring-data-jpaspring-data

@Transactional annotation on save/saveAll vs @Transactional annotation on custom method which calls saveAll


Commit multiple tables at once in spring boot did not help

I am new to Spring (Boot) Data JPA. I am trying to insert data into 2 different tables using repo1.saveAll and repo2.saveAll from within a method that has the transactional annotation.

@Autowired
Table1Repo repo1; //corresponding to Table1; interface extending JPA's CRUDRepository
@Autowired
Table2Repo repo2; //corresponding to Table2; interface extending JPA's CRUDRepository

@Transactional
void saveMyData(List<Table1Entity> dataForTable1,List<Table2Entity> dataForTable2){
//i want the commit to happen AFTER both statements have been completed 
repo1.saveAll(dataForTable1)
repo2.saveAll(dataForTable2)
}

I expect the data to be committed to both the tables together or nothing with the @Transactional annotation.

But when I check the tables I find that the after saveAll to table1 is completed, the data becomes available in table1 in the Database (as checked from the SQL Developer studio) and then the saveAll to table2 proceeds. This violates the atomicity of a transaction. I was expecting @Transactional annotation to take care of this.

When I dug in, I found out that the save/saveAll/delete/deleteAll etc. methods of the SimpleJPARepository are also already annotated with @Transactional annotation. Is that the reason why the @Transactional annotation that I have used for my method gets ignored and the data gets committed at each saveAll call made from within my method thanks to the saveAll method's @Transactional annotation meaning that each saveAll call is executed within its own transaction. Does it mean using @Transactional on a custom method like saveMyData has no meaning when calling saveAll method on the repo from within that method?


Solution

  • Transaction annotation is executed as a single work unit from the method started and guarantees All or Nothing, i.e. atomicity. In other words, even if @Transactional is attached to a method, it is not separated into a separate transaction unless the requires_new option is attached. The suspected problem is when a method annotated with @Transactional is called from a method in an inner class that is not annotated with @Transactional. In that case, @Transactional will not work as expected because the spring bean is acting as a proxy.