java - Spring @Transactional 对服务和非服务方法的不同行为?
问题描述
我有一个具有标准架构(控制器-> 服务-> 存储库)的 Spring Boot 2.3 REST 应用程序。出于审计目的,我插入了一个薄层(某种Mediator),以便我将所有请求持久化到某个特定的服务方法,无论它们是否成功持久化或抛出异常并回滚事务。例子:
@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;
}
}
}
因此我遇到了一个奇怪的情况:如果我将@Transactional
放在 Mediator 的方法上(上面的示例),JPA Repositories 中的所有操作都会成功持久化。如果我将其@Transactional
放在 ServiceImpl 方法上(下面的示例)并且不再放在 Mediator 上,则不会运行其中一个删除查询,尽管其余查询执行得很好。假设我的 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());
}
}
就事务而言,这两种方法之间唯一明显的区别是,在第一种情况下,我对每个 Mediator 调用都有这个:
o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(909894553<open>)] for JPA transaction
而在第二种情况下,我有这个:
tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
我猜想直接用@Transactional
(我在 Mediator 中所做的)注释 bean 的方法和用相同的东西(我们通常通过注释 ServiceImpl 方法来注释bean 的(即注入接口的实现)方法)之间存在区别),但我不确定也无法找出这种奇怪行为的原因。有谁知道为什么会这样?
解决方案
我猜这种行为差异是由于默认启用的 Spring OpenSessionInView 造成的。您必须在 application.yml 中设置
spring:
jpa:
open-in-view: false
请参阅OSIV
推荐阅读
- python - 如何将此列表附加保存功能修复到文件?
- r - 组合列和计数组合(对)
- python - Python:获取方法使用的属性列表
- sql-server - 如何查找用户的总登录时间?
- python - 为什么while循环得到不正确的结果
- foreign-keys - 在具有两个外键的 Power BI 中使用 LOOKUPVALUE() 时出现依赖性错误
- ruby-on-rails - Activeadmin 自定义过滤器标签未注册 I18n 区域设置
- python - 为什么我在顶层窗口中的进度条没有移动?
- azure-devops - 如何修复 Azure Devops 中的“命名空间‘Y’中不存在类型或命名空间名称‘X’”错误
- parameters - 如何通过 JMeter 5.1.1 中的“随请求发送参数”传递带有特殊字符的参数