共计 1897 个字符,预计需要花费 5 分钟才能阅读完成。
在 Spring Boot 中,造成事务不主动回滚的场景有很多,比方以下这些:
- 非 public 润饰的办法中的事务不主动回滚;
- 当 @Transactional 遇上 try/catch 事务不主动回滚;
- 调用类外部的 @Transactional 办法事务不主动回滚;
- 抛出查看异样时事务不主动回滚;
- 数据库不反对事务,事务也不会主动回滚。
那么对于下面的这些场景,咱们应该如何解决呢?接下来咱们一一来看。
1. 非 public 办法解决方案
非 public 办法中事务不回滚的间接起因是,在非 public 办法上增加的 @Transactional 关键字是有效的,也就是此办法自身是以非事务的形式运行的,所以它当然不会主动回滚事务了。
因为 @Transactional 应用的是 Spring AOP 实现的,而 Spring AOP 是通过动静代理实现的,而 @Transactional 在生成代理时会判断,如果办法为非 public 润饰的办法,则不生成代理对象,这样也就没方法主动回滚事务了,它的局部实现源码如下:
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
// Don't allow no-public methods as required.
// 非 public 办法,设置为 null
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}
// 前面代码省略....
}
此问题的解决方案是将办法的权限修饰符改为 public 即可。
2.try/catch 解决方案
当程序中呈现了 try/catch 代码时,事务不会主动回滚,这是因为 @Transactional 注解在其实现时,须要感知到异样才会主动回滚,而用户自行在代码中退出了 try/catch 之后,@Transactional 就无奈感知到异样了,那么也就不能主动回滚事务了。
此问题的解决方案有两种:一种是在 catch 中将异样从新抛出去,另一种是应用代码手动将事务回滚。
解决方案 1:将异样从新抛出
解决方案 2:应用代码手动回滚事务
除了解决方案 1 这种不是很敌对的回滚事务的形式之外,咱们还能够抉择更加敌对的,不报错,但能够回滚事务的形式,其外围实现代码如下:
3. 调用外部 @Transactional 办法解决方案
调用类外部 @Transactional 的办法不主动回滚事务的起因是,@Transactional 是基于 Spring AOP 实现的,而 Spring AOP 又是基于动静代理实现的,而当调用类外部的办法时,不是通过代理对象实现的,而是通过 this 对象实现的,这样就绕过了代理对象,从而事务就生效了。
此时咱们的解决方案是给调用的办法上也加上 @Transactional,具体实现代码如下:
4. 查看异样的事务解决方案
所谓的查看异样(Checked Excetion)指的是编译器要求开发者必须解决的异样,如下图所示:
查看异样不回滚事务的起因是因为,@Transactional 默认只回滚运行时异样 RuntimeException 和 Error,而对于查看异样默认是不回滚的。
此问题的解决方案是给 @Transactional 注解上,增加 rollbackFor 参数并设置 Exception.class 值即可,具体实现代码如下:
5. 数据库不反对事务的解决方案
当咱们在程序中增加了 @Transactional,相当于给调用的数据库发送了:开始事务、提交事务、回滚事务的指令,然而如果数据库自身不反对事务,比方 MySQL 中设置了应用 MyISAM 引擎,因为它自身是不反对事务的,这种状况下,即便在程序中增加了 @Transactional 注解,那么仍然不会有事务的行为,也就不会执行事务的主动回滚了。
在这种状况下,咱们只须要设置 MySQL 的引擎为 InnoDB 就能够解决问题了,因为 InnoDB 是反对事务的 ,当然 MySQL 5.1 之后的默认引擎就是 InnoDB,引擎的设置分为以下两种状况:
在新建表时设置数据库引擎:
在批改表时设置数据库引擎:
PS:也就是数据库的引擎是和表间接相干的,咱们只须要正确的设置引擎之后,事务就能够失常的执行了。
总结
本文咱们介绍了 5 种事务不主动回滚的场景和相应的解决方案,开发者应该依据本人的理论状况,抉择适合本人解决方案进行解决。
是非审之于己,毁誉听之于人,得失安之于数。
公众号:Java 面试真题解析
面试合集:https://gitee.com/mydb/interview