首页 > 技术文章 > @Transactional 什么情况下会失效?

IamYoung 2021-02-04 16:16 原文

正题:

  1. @Transactional 应用在非 public 修饰的方法上
    原因:Spring AOP代理时,TransactionInterceptor(事务拦截器)里面调用的 computeTransactionAttribute 方法会判断目标方法的修饰符是否为 public。
  2. 同一个类中的方法调用
    原因:this 调用是真实对象,并不是通过 AOP 代理对象调用。
    例子:方法 A 和方法 B 在同一个类,B 有而 A 没有注解 @Transactional,A 调用 B。当外部调用 A 时,B 事务不会起效。
  3. 异常被“吃了”
    例子:try-catch 把异常捕获了,没有抛出来。
  4. 异常类型不对
    原因:Spring 默认只回滚 Error 和继承自 RuntimeException 的异常。
    用法:@Transactional(rollbackFor=Exception.class)
  5. 事务传播特性设置错误
    例子:类 A 的 方法 a 使用默认模式 Propagation.REQUIRED,类 B 中的方法 b 使用模式  Propagation.REQUIRES_NEW,a调用 b。a 抛出异常,b 不会回滚。b 抛出异常,a 会回滚。
    用法:@Transactional(propagation=Propagation.REQUIRES_NEW)
  6. 数据库引擎不支持事务
    例子:MySQL数据库默认引擎 innodb 支持事务,但 myisam 不支持。
  7. 项目没有开启事务 
    原因:应用类没有添加注解 @EnableTransactionManagement。

 

题外话:

  1. @Transactional 保证方法内多个数据库操作要么同时成功,要么同时失败
  2. @Transactional 可以作用在类、类方法、接口
  3. Propagation 属性:
    PROPAGATION_REQUIRED:如果不存在外层事务,就主动创建事务;否则使用外层事务
    PROPAGATION_SUPPORTS:如果不存在外层事务,就不开启事务;否则使用外层事务
    PROPAGATION_MANDATORY:如果不存在外层事务,就抛出异常;否则使用外层事务
    PROPAGATION_REQUIRES_NEW:总是主动开启事务;如果存在外层事务,就将外层事务挂起
    PROPAGATION_NOT_SUPPORTED:总是不开启事务;如果存在外层事务,就将外层事务挂起
    PROPAGATION_NEVER:总是不开启事务;如果存在外层事务,则抛出异常
    PROPAGATION_NESTED:如果不存在外层事务,就主动创建事务;否则创建嵌套的子事务

推荐阅读