Reputation: 877
I am building an application with Spring Boot v2.1.3.RELEASE and Hibernate v5.3.6.
Previously, I asked a question about how to rollback with @Transactional across multiple services/repositories. I got what I needed by linking my Entities together with @OneToOne and @OneToMany annotations.
Now im facing a new problem. Inside a function in a single service, I am saving two separate lists of entities. One list saves, and the other list fails due to a Unique Key Constraint Violation. This is expected to fail since im testing.
But, I have not figured out how to annotate my Service or method with @Transactional, so that when the second list fails to save, it will also roll back any successful saves of the first list.
For example:
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
protected void saveLists() {
List<Object> list1 = this.repository.getListOne();
List<Object> list2 = this.repository.getListTwo();
//Loop through list one and do some manipulation
//Loop through list two and do some manipulation
this.repository.saveAll(list1); // this saves all successfully
this.repository.saveAll(list2); // this has unique key exception
// rollback both list1 and list2 changes
}
In the above example, the data from list1 gets saved successfully and appears in the database after the exception from list2 is thrown.
I thought that since they are in the same service and the same method, using the same repository, that they would be using the same transaction, and that Hibernate would not commit the transaction until it leaves this method with no errors.
But that does not seem to be the case. As the data for list one is getting committed and not rolled back.
Is there something I am missing about the @Transactional annotation? How can I make both saves work as a single transaction and rollback both, upon an error thrown from either save?
Upvotes: 2
Views: 5235
Reputation: 759
Hello @Transactional doesn't work on private or protected method, your method should be public. Why? Because spring should create a proxy to deal with the transaction demarcation and behavior. Since there is no possibility to proxy a protected or private method, your annotation is simply ignore .
Upvotes: 1
Reputation: 418
you need just to annotate with @Transactional the method of the service which is called in the controller not this method. Or you can annotate the Service class with @Transactional
Upvotes: 0