安徽建海建设工程有限公司网站,免费咨询电话,可以翻外墙的浏览器,为中小型企业构建网站Spring事务失效的几种情况及其解决方案
方法权限修饰符不是public
Transactional 使用的是 Spring AOP 实现的#xff0c;而 Spring AOP 是通过动态代理实现的#xff0c;而 Transactional 在生成代理时会判断#xff0c;如果方法为非 public 修饰的方法#xff0c;则不生…Spring事务失效的几种情况及其解决方案
方法权限修饰符不是public
Transactional 使用的是 Spring AOP 实现的而 Spring AOP 是通过动态代理实现的而 Transactional 在生成代理时会判断如果方法为非 public 修饰的方法则不生成代理对象这样也就没办法自动回滚事务了它的部分实现源码如下
protected TransactionAttribute computeTransactionAttribute(Method method, Class? targetClass) {// Dont allow no-public methods as required.// 非 public 方法设置为 nullif (allowPublicMethodsOnly() !Modifier.isPublic(method.getModifiers())) {return null;}// 后面代码省略....}解决方案
将方法的权限修饰符改为 public 即可
Try/Catch
当程序中出现了 try/catch 代码时事务不会自动回滚这是因为 Transactional 注解在其实现时需要感知到异常才会自动回滚而用户自行在代码中加入了 try/catch 之后Transactional 就无法感知到异常了那么也就不能自动回滚事务了。
解决方案
将异常重新抛出
Final修饰符
spring 事务底层使用了 aop也就是通过 jdk 动态代理或者 cglib帮我们生成了代理类在代理类中实现的事务功能。但如果某个方法用 final 修饰了那么在它的代理类中就无法重写该方法而添加事务功能。
注意如果某个方法是 static 的同样无法通过动态代理变成事务方法。
解决方案
不使用final修饰符
同一个类内部调用
在同一个类中的方法直接内部调用时直接调用了 this 对象的方法没有使用代理对象的方法因此会导致事务失效。
解决方案
在该 Service 类中注入自己
此时注入的就是代理类
在该 Service 类中使用 AopContext.currentProxy() 获取当前实例的代理对象。
数据库不支持事务
当我们在程序中添加了 Transactional相当于给调用的数据库发送了开始事务、提交事务、回滚事务的指令但是如果数据库本身不支持事务比如 MySQL 中设置了使用 MyISAM 引擎因为它本身是不支持事务的这种情况下即使在程序中添加了 Transactional 注解那么依然不会有事务的行为也就不会执行事务的自动回滚了。
解决方案
设置 MySQL 的引擎为 InnoDB 就可以解决问题了因为 InnoDB 是支持事务的