简体   繁体   English

Spring @Transactional 在服务和非服务方法上的不同行为?

[英]Spring @Transactional different behavior on Service and non-Service methods?

I have a Spring Boot 2.3 REST application with a standard architecture (controller -> service -> repository).我有一个具有标准架构(控制器 -> 服务 -> 存储库)的 Spring Boot 2.3 REST 应用程序。 For auditing purposes, I inserted a thin layer (some kind of a Mediator ), so that I persist all the requests to some specific service method regardless they are successfully persisted or an exception is thrown and the transaction is rollbacked.出于审计目的,我插入了一个薄层(某种Mediator ),以便我将所有请求持久化到某个特定的服务方法,无论它们是成功持久化还是抛出异常并回滚事务。 Example:例子:

@Component
public class Mediator {

    private final Service service;
    private final AuditService auditService;

    public Mediator(Service service, AuditService auditService) {
        this.service = service;
        this.auditService = auditService;
    }

    @Transactional
    public void saveReport(Report report) {
        try {
            service.saveReport(report);
            auditService.saveReport(report); 
        } catch (Exception exception) {
            auditService.saveReport(report, exception);
            throw exception;
        }
    }
}

Thus I encountered a weird situation: if I place the @Transactional on the Mediator's method (example above), all the operations in the JPA Repositories are successfully persisted.于是我遇到了一个奇怪的情况:如果我把@Transactional放在Mediator 的方法上(上面的例子),JPA Repositories 中的所有操作都成功持久化了。 If I place the @Transactional on the ServiceImpl method instead (example below) and no longer on the Mediator, one of the delete queries is not ran, although the rest of the queries are executed just fine.如果我将@Transactional放在 ServiceImpl 方法上(下面的示例)并且不再放在 Mediator 上,则不会运行其中一个删除查询,尽管其余查询执行得很好。 Suppose my ServiceImpl looks something like:假设我的 ServiceImpl 看起来像:

@Service
public class ServiceImpl implements Service {

    private final RepositoryA repositoryA;
    private final RepositoryB repositoryB;

    public ServiceImpl(RepositoryA repositoryA, RepositoryB repositoryB) {
        this.repositoryA = repositoryA;
        this.repositoryB = repositoryB;
    }

    @Transactional
    public void saveReport(Report report) {
        repositoryA.save(report.getA());
        repositoryB.save(report.getB());
        repositoryB.delete(report.getSomethingElse());
    }
}

The only visible difference between the two approaches with respect to the Transactions is that in the first scenario, I have this for each Mediator call:关于事务的两种方法之间唯一明显的区别是,在第一个场景中,我对每个 Mediator 调用都有这个:

o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(909894553<open>)] for JPA transaction

while in the second scenario, I have this:在第二种情况下,我有这个:

tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation

I guess there is a difference between annotating directly a bean's method with @Transactional (what I do in the Mediator) and annotating a bean's ( that is the implementation of the interface injected ) method with the same thing (what we usually do by annotating a ServiceImpl method), but I am not sure and cannot spot the reason for this weird behaviour.我想直接用@Transactional注释 bean 的方法(我在 Mediator 中所做的)和用相同的东西注释 bean 的(即接口注入的实现)方法(我们通常通过注释一个ServiceImpl 方法),但我不确定也无法找出这种奇怪行为的原因。 Does anyone have an idea why this happens?有谁知道为什么会发生这种情况?

I guess that this difference in behavior is due to Spring OpenSessionInView which is enabled by default.我想这种行为差异是由于 Spring OpenSessionInView 默认启用的。 You must set in application.yml您必须在 application.yml 中设置

spring:
  jpa:
    open-in-view: false

Please see OSIV请参阅OSIV

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM