I have a parent transaction at controller layer, but I want to start a new transaction when I call a repository, to achieve this I tried annotating Repository interface as below
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{ }
However this seems to not start a new transaction upon calls to EventRepo#save. Why?
Here is my service layer.
public interface IApplicationService {
void save(Event event);
}
@Service
public class ApplicationService implements IApplicationService {
@Autowired
private EventRepo eventRepo;
@Override
public void save(Event event) {
eventRepo.save(event);
}
}
It is in turn called from controller layer
@RequestMapping(value="/{indicator}", method=RequestMethod.POST)
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
@ResponseBody
public String processRequest(@PathVariable Integer indicator) {
Event event = new Event("Student1");
service.save(event);
if(indicator != 0) {
throw new RuntimeException();
}
return "Success";
}
However everything works perfectly if I annotate Service interface with @Transactional
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface IApplicationService {
void save(Event event);
}
When I say working what is mean is, if I run the below curl commands I will see 2 rows in h2 db for Event entity
curl -X POST http://localhost:8080/1
curl -X POST http://localhost:8080/0
I understand it is good to control transactions at Service layer then repository or controller layer, constructing situation this way makes it easy to demonstrate the problem.
Spring boot starter version is 2.5.6 below dependencie have versions managed by springboot starter
- spring-boot-starter-data-jpa
- spring-boot-starter-web
- lombok
- h2
Here is a thread that suggests it should be ok to annotate Repository layer although discourages it. @Transactional on a JpaRepository
CodePudding user response:
In this Spring article we can read the following:
Additionally, we can get rid of the @Transactional annotation for the method as the CRUD methods of the Spring Data JPA repository implementation are already annotated with @Transactional.
To me, this means that whatever @Transactional
annotation you add to your EventRepo
will be overridden by the @Transactional
annotation mentioned above in the CRUD methods. Having said that, I really doubt @Transactional
annotation has any effect in JpaRepository
methods. It would have in your own custom methods, but it seems to me that it has none in the inherited methods.
CodePudding user response:
In order to apply your own transactional settings in EventRepo#save
override the save method:
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{
@Override
Event save(Event event);
}
Explanation
Spring ignores your @Transactional
annotation because it cannot find the save
method in the EventRepo
proxy and applies the default transaction settings from the parent CrudRepository
interface.
Further reading: How Does Spring @Transactional Really Work?