@Transactional 什么情况下会失效?
正题:
- @Transactional 应用在非 public 修饰的方法上
原因:Spring AOP代理时,TransactionInterceptor(事务拦截器)里面调用的 computeTransactionAttribute 方法会判断目标方法的修饰符是否为 public。 - 同一个类中的方法调用
原因:this 调用是真实对象,并不是通过 AOP 代理对象调用。
例子:方法 A 和方法 B 在同一个类,B 有而 A 没有注解 @Transactional,A 调用 B。当外部调用 A 时,B 事务不会起效。 - 异常被“吃了”
例子:try-catch 把异常捕获了,没有抛出来。 - 异常类型不对
原因:Spring 默认只回滚 Error 和继承自 RuntimeException 的异常。
用法:@Transactional(rollbackFor=Exception.class) - 事务传播特性设置错误
例子:类 A 的 方法 a 使用默认模式 Propagation.REQUIRED,类 B 中的方法 b 使用模式 Propagation.REQUIRES_NEW,a调用 b。a 抛出异常,b 不会回滚。b 抛出异常,a 会回滚。
用法:@Transactional(propagation=Propagation.REQUIRES_NEW) - 数据库引擎不支持事务
例子:MySQL数据库默认引擎 innodb 支持事务,但 myisam 不支持。 - 项目没有开启事务
原因:应用类没有添加注解 @EnableTransactionManagement。
题外话:
- @Transactional 保证方法内多个数据库操作要么同时成功,要么同时失败
- @Transactional 可以作用在类、类方法、接口
- Propagation 属性:
PROPAGATION_REQUIRED:如果不存在外层事务,就主动创建事务;否则使用外层事务
PROPAGATION_SUPPORTS:如果不存在外层事务,就不开启事务;否则使用外层事务
PROPAGATION_MANDATORY:如果不存在外层事务,就抛出异常;否则使用外层事务
PROPAGATION_REQUIRES_NEW:总是主动开启事务;如果存在外层事务,就将外层事务挂起
PROPAGATION_NOT_SUPPORTED:总是不开启事务;如果存在外层事务,就将外层事务挂起
PROPAGATION_NEVER:总是不开启事务;如果存在外层事务,则抛出异常
PROPAGATION_NESTED:如果不存在外层事务,就主动创建事务;否则创建嵌套的子事务