记一次Spring中@Transactional未生效问题

背景

在controller方法上增加了@Transactional注解,实际运行过程中方法出现了Exception导致方法执行失败,但是发现已经执行的insert操作并没有回滚

@Transactional可能失效的场景

  1. 一个有@Transactional的方法被没有@Transactional方法调用时,会导致Transactional作用失效
    产生原因: Spring AOP代理造成,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

  2. 对非public方法进行事务注解。@Transactional 将会失效
    产生原因: Spring AOP代理时,事务拦截器在目标方法前后进行拦截,DynamicAdvisedInterceptor的intercept 方法会获取Transactional注解的事务配置信息,因为在Spring AOP 代理时, TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法,这个方法会获取Transactional 注解的事务配置信息。他会首先校验事务方法的修饰符是不是public,不是 public则不会获取@Transactional 的属性配置信息。

  3. Transactional 事务配置属性中的propagation 属性配置的问题
    产生原因:
    TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常

  4. 异常被catch之后没有throw

  5. 数据库引擎不支持事务

  6. 没有被 Spring 管理

  7. 数据源没有配置事务管理器

  8. 异常类型错误

  9. 没有开启事务管理

问题排查解决

  1. 经排查以上情况均没问题
  2. 移动@Transactional注解至service接口,发现事务生效
  3. 经分析确认是因为注解位置导致事务失效

原因分析

  1. spring中,@Transactional注解仅对spring的context生效,如果class没有注册到spring的context中,则事务管理器将无法生效
  2. spring中context和spring mvc的上下文容器是隔离开的,mvc容器是spring容器的一个子容器,子容器中可以访问父容器,但父容器无法访问子容器
  3. controller会注册到mvc子容器中,而@Transactional对spring父容器生效,故当@Transactional在controller时无法回滚事务
  4. controller能否注册到spring父容器而非mvc子容器,答案:不能,因为当controller注册到spring父容器后mvc子容器中就没有,http的请求path就无法正确映射,请求接口时就会404
  5. 能否只使用mvc容器而不使用spring容器,答案:可以,mvc容器更加轻量级,但是spring容器扩展性更好,可以方便的集成其他框架

小短腿的个人公众号上线啦,后续技术分享将优先在公众号进行哈,大家可以关注公众号,小短腿有什么新的分享会及时同步哈
记一次Spring中@Transactional未生效问题

上一篇:Spring 中的事务处理


下一篇:一口气说出 6种,@Transactional注解的失效场景(好文章!!)