You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring @Transactional在Service与非Service类方法上的行为差异问题

问题核心原因

你遇到的差异不是普通Bean和接口实现类加@Transactional的逻辑差异,Spring的事务代理逻辑对所有Spring管理的Bean都是统一的,本质原因是第二种场景下ServiceImpl的@Transactional注解没有实际生效,事务没有正常开启。

两种场景的差异拆解

场景1:@Transactional加在Mediator上(事务正常生效)

此时外层Mediator方法开启了事务,ServiceImpl的方法默认事务传播行为为REQUIRED,会直接加入当前已有的事务:

  • JpaTransactionManager会创建和当前事务绑定的EntityManager,生命周期和事务完全一致,事务提交前会自动将持久化上下文中所有待执行的操作(包括save、delete)全部flush到数据库,所以所有操作都能正常执行。
  • 输出的日志就是你看到的Opened new EntityManager for JPA transaction。

场景2:@Transactional加在ServiceImpl上(事务未生效)

事务未生效时,Spring无法拿到事务绑定的EntityManager,只能给每个Repository操作创建临时的共享EntityManager,用完就销毁:

  • JpaRepository的save操作对于新实体,Hibernate默认会自动触发flush将数据写入数据库,所以你能看到save操作生效。
  • 而delete操作默认不会自动触发flush,操作会停留在持久化上下文缓存中,随着临时EntityManager销毁直接丢失,所以你看不到delete执行。
  • 输出的日志就是你看到的Creating new EntityManager for shared EntityManager invocation。

排查事务未生效的常见原因

按优先级逐个检查:

  1. 注解包错误:确认ServiceImpl上的@Transactional是org.springframework.transaction.annotation.Transactional,不要误用javax/jakarta.transaction包下的同名注解,Spring事务管理器只识别自身包下的注解。
  2. 方法/类访问修饰符错误:@Transactional默认只对public方法生效,检查ServiceImpl类和saveReport方法是否是public修饰。
  3. 代理未生效:在Mediator的构造方法打断点,查看注入的Service实例是否是代理类(类名带有$$EnhancerBySpringCGLIB或$Proxy前缀),如果是原生的ServiceImpl类,说明代理未生成,事务自然不生效。

额外补充

你当前的审计逻辑存在缺陷:如果@Transactional加在Mediator上,业务方法抛出异常时会触发整个事务回滚,审计日志也会跟着回滚,达不到你要求的「无论业务成功失败都要存储审计日志」的需求。你可以给AuditService的saveReport方法单独加@Transactional(propagation = Propagation.REQUIRES_NEW),让审计日志在独立事务中提交,不受业务事务回滚的影响。

内容的提问来源于stack exchange,提问作者Daniel Pop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 19:48:00