Springboot事务失效的几种情况解读
作者:Eocc
这篇文章主要介绍了Springboot事务失效的几种情况解读,因为Spring AOP默认使用动态代理,会给被代理的类生成一个代理类,事务相关的操作都通过代理来完成,使用内部方法调用时,使用的是实例调用,没有通过代理类调用方法,因此事务不会检测到失败,需要的朋友可以参考下
1. 内部调用
使用一个没有事务的方法调用一个有事务的方法,失败后不会进行回滚:
@Transactional public int update(Admin admin) { int update = mapper.update(admin); return update; } public int invokeUpdate(Admin admin) { return update(admin); }
这时因为Spring AOP默认使用动态代理,会给被代理的类生成一个代理类,事务相关的操作都通过代理来完成,使用内部方法调用时,使用的是实例调用,没有通过代理类调用方法,因此事务不会检测到失败。
解决方法就是使用代理类调用事务方法:
在类内部注入本类
@Autowired private AdminService service; // 然后再调用 public int invokeUpdate(Admin admin) { return service.update(admin); }
通过ApplicationContext引入
((AdminService)ApplicationContext.getBean("adminService")).invokeUpdate(Admin admin);
通过AopContext引入
((AdminService)AopContext.currentProxy()).invokeUpdate(Admin admin);
2. 没有指定监听的Exception
@Transactional只会监听RuntimeException,当抛出其他异常时,不能正常捕获,也就不会回滚。
解决方法:
- 手动捕获异常,然后包装为RuntimeException抛出
- 使用roobackFor属性指定需要捕获的异常:
@Transactional(rollbackFor = Exception.class) public int update(Admin admin) { int update = mapper.update(admin); return update; }
3. 内部异常被catch
源码:org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
关键部分:
try { //开启事务 //这个地方也可以看出是通过代理来实现的事物,如果绕过代理调用(如内部调用),则不会开启事务 Object var8 = invocation.proceedWithInvocation(); return var8; } catch (Throwable var13) { //如果抛出异常,回滚事务 //如果异常在方法内部被catch了,这个地方就不会接收到异常,就不会回滚事务 if (txAttr.rollbackOn(var13)) { if (var13 instanceof RuntimeException) { throw (RuntimeException)var13; } throw new TransactionAspectSupport.ThrowableHolderException(var13); } throwableHolder.throwable = var13; var9 = null; } finally { //提交事务 this.cleanupTransactionInfo(txInfo); }
到此这篇关于Springboot事务失效的几种情况解读的文章就介绍到这了,更多相关Springboot事务失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!