Home > Back-end >  @Transactional has no effect on JpaRepository
@Transactional has no effect on JpaRepository

Time:10-30

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?

  • Related