自注入调用事务方法时异常未触发回滚的解决方案咨询
解决方案:修复事务不回滚问题
问题根源
你遇到的问题核心有两点:
- 内部调用导致事务代理失效:Spring事务基于动态代理实现,同一个类内部方法调用(比如
c()直接调用a()、b())不会触发代理逻辑,a()和b()上的@Transactional注解完全不生效,所有操作都处于c()的事务上下文里。 - 检查异常不触发默认回滚:
SQLException属于检查型异常,Spring默认的@Transactional仅对运行时异常(RuntimeException)和错误(Error)执行回滚,因此抛出该异常不会触发事务回滚,导致已执行的修改被提交。
方案一:调整事务回滚规则(快速解决)
直接修改c()的@Transactional注解,指定回滚的异常类型包含SQLException,确保异常触发时整个事务回滚:
@Transactional(rollbackFor = SQLException.class) void c() { serviceClass.a(); serviceClass.b(); }
注:此方案未解决内部代理失效问题,a()和b()的事务注解仍不生效,所有操作共用c()的事务。
方案二:修复内部调用的代理失效问题(彻底解决独立事务需求)
若需要a()和b()各自生效独立事务,需让调用走代理逻辑,有两种常用方式:
方式1:获取自身代理对象调用
在类中注入ApplicationContext,初始化时获取当前类的代理实例,用代理对象调用方法:
@Service public class YourService { @Autowired private ApplicationContext context; private YourService selfProxy; @PostConstruct public void init() { // 获取自身代理实例 selfProxy = context.getBean(YourService.class); } @Transactional public void a() { // 业务逻辑 } @Transactional(rollbackFor = SQLException.class) public void b() throws SQLException { throw new SQLException(); } @Transactional public void c() { // 通过代理调用,触发事务注解逻辑 selfProxy.a(); selfProxy.b(); } }
方式2:拆分服务类(推荐,符合单一职责)
将a()和b()拆分到不同的Service类中,跨类调用会自动走代理,事务注解正常生效:
@Service public class AService { @Transactional public void a() { // 业务逻辑 } } @Service public class BService { @Transactional(rollbackFor = SQLException.class) public void b() throws SQLException { throw new SQLException(); } } @Service public class CService { @Autowired private AService aService; @Autowired private BService bService; @Transactional public void c() { aService.a(); bService.b(); } }
方案三:使用AspectJ编织事务(特殊场景可选)
若必须保留类内部调用且生效事务,可开启AspectJ编译/运行时编织,替代Spring动态代理。需在配置类添加:
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
并引入AspectJ相关依赖。此方式复杂度较高,仅适合有特殊需求的场景,不推荐常规业务使用。
内容的提问来源于stack exchange,提问作者lalala
相关产品推荐
相关产品推荐

