控制器层存在父事务时,JpaRepository上的@Transactional(REQUIRES_NEW)注解未生效原因排查
Let’s break down exactly why your Repository-level transaction configuration isn’t behaving as expected, while the Service-level one works perfectly:
The Root Cause: @Transactional Doesn’t Inherit to Inherited Methods
The core issue boils down to Java’s annotation rules: the @Transactional annotation does not have the @Inherited meta-annotation. This means when you add @Transactional(REQUIRES_NEW) to your EventRepo interface, it won’t automatically apply to methods inherited from JpaRepository (like the save() method you’re calling).
Here’s the step-by-step breakdown:
- Spring Data JPA’s default transaction behavior: CRUD methods like
save()fromCrudRepository/JpaRepositorycome with a default@Transactional(propagation = Propagation.REQUIRED)annotation. This means they’ll join an existing transaction if one is already active. - Your Repository interface annotation doesn’t override defaults: Since
@Transactionalisn’t inherited, adding it toEventRepodoesn’t change the behavior of the inheritedsave()method. The method still uses the defaultREQUIREDpropagation. - What happens in your controller flow:
- The controller’s
processRequest()runs in aREQUIRES_NEWtransaction. - You call
service.save(event)—but since yourApplicationServicehas no transactional annotations, this is a plain method call (no AOP proxy wraps it). - When
eventRepo.save(event)executes, it uses the defaultREQUIREDpropagation, so it joins the controller’s existing transaction. - If the controller throws a
RuntimeException, the entire controller transaction rolls back—including thesave()operation.
- The controller’s
Why the Service-Level Annotation Works
When you add @Transactional(REQUIRES_NEW) to your IApplicationService interface:
- The
save()method is declared directly in this interface, so the@Transactionalannotation applies directly to it (no inheritance is involved here). - Spring creates an AOP proxy for your
ApplicationServicebean. When the controller callsservice.save(event), it goes through this proxy, which starts a new, independent transaction. - Even if the controller’s transaction rolls back later, the Service’s transaction has already committed the
save()operation, so the record remains in the database.
How to Fix the Repository-Level Scenario
If you want to make REQUIRES_NEW work on the Repository layer, you need to explicitly override the save() method and apply the annotation directly to it:
public interface EventRepo extends JpaRepository<Event, Integer> { @Override @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW) <S extends Event> S save(S entity); }
By doing this, the @Transactional(REQUIRES_NEW) annotation is directly tied to the save() method, and Spring Data JPA will use this configuration instead of the default.
内容的提问来源于stack exchange,提问作者Pavan Kumar

