@Transactional 注解的作用就是保证方法内的多个数据库操作具有事务特性,即要么都成功提交,要么都失败回滚。但是错误的使用会导致事务失效,以下是总结的九种可能发生事务失效的原因
1、@Transactional 用在非 public 修饰的方法上
事务拦截器在目标方法执行前后进行拦截,内部会调用方法来获取 Transactional 注解的事务配置信息,调用前会检查目标方法的修饰符是否为 public,不是 public 则不会获取 @Transactional 的属性配置信息。
2、@Transactional 用于接口上
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。
3、@Transactional 注解属性 propagation 设置以下三种可能导致无法回滚
SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
4、同一类中加 @Transactional 方法被无 @Transactional 的方法调用,事务失效
如果在同一个类中的不同方法调用中,A方法调用B方法,A中无事务,B中有事务,那事务不会生效。因为Spring采用动态代理实现对bean的管理和切片,它为每个class都会生成一个代理对象。只有在代理对象之间调用时,可以触发切面逻辑。而同一个 class 中,方法A调用方法B,且方法A无事务,调用的是原对象的方法,而不是通过代理对象,因此Spring无法切换到这次调用,也就无法通过注解保证事务性了。
5、@Transactional 方法内异常被捕获
事务在调用业务方法之前就开始了,业务方法执行完毕之后才执行提交或回滚,而事务是否执行取决于是否抛出运行异常。如果抛出了运行异常并在你的业务方法中没有 catch 到的话,事务就会回滚。但是如果异常被用户代码手动捕获了的话,那这个异常就不会抛给 spring 切面,那整个事务会被正常提交。如果非要catch就一定要抛出 throw new RuntimeException(),或者注解中指定抛异常类型 @Transactional(rollbackFor=Exception.class)
6、数据库不支持事务
也可能是数据库不支持事务,比如 MySQL 使用的 MyISAM 存储引擎
7、@Transactional 的注解 rollbackFor 属性设置错误
rollbackFor 默认是 RuntimeException 和 Error 及子类抛出,就会回滚;如果 rollbackFor 指定了异常类型,那只有指定的异常及子类发生才会回滚
8、Spring 的配置文件中未配置开启事务注解
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
9、没有引入 jbdc 或 jpa 包,不会开启事务
Spring Boot 引入了 jbdc 或 jpa 包,会默认开启事务注解。若未引入这两个包,需要在启动类加上 @EnableTransactionManagement 进行配置
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98652.html