可爱风格网站,网站类软文,wordpress自动添加视频播放,制作静态网站引言
Spring事务一般我们采用注解实现#xff0c;但是我们构造事务实现的时候常常没察觉失效的情况#xff0c;本篇文章总结事务失效的六大情况#xff0c;帮助我们深刻理解事务失效的边界概念
1. 方法自调用
这个主要是针对声明式事务的#xff0c;经过前面的介绍但是我们构造事务实现的时候常常没察觉失效的情况本篇文章总结事务失效的六大情况帮助我们深刻理解事务失效的边界概念
1. 方法自调用
这个主要是针对声明式事务的经过前面的介绍小伙伴们其实也能够看出来声明式事务底层其实就是 AOP所以在声明式事务中我们我们拿到的服务类并不是服务类本身而是一个代理对象在这个代理对象中的代理方法中自动添加了事务的逻辑所以如果我们直接方法自调用没有经过这个代理对象事务就会失效。
我写一段伪代码小伙伴们一起来看下
public class UserService{Transactionalpublic void sayHello(){}
}此时如果我们在 UserController 中注入 UserService那么拿到的并不是 UserService 对象本身而是通过动态代理为 UserService 生成的一个动态代理类这个动态代理就类似下面这样伪代码
public class UserServiceProxy extends UserService{public void sayHello(){try{//开启事务//调用父类 sayHello//提交事务}catch(Exception e){//回滚事务}}
}所以你最终调用的并不是 UserService 本身的方法而是动态代理对象中的方法。
因此如果存在这样的代码
public class UserService{Transactionalpublic void sayHello(){}public void useSayHello(){sayHello();}
}在 useSayHello 中调用 sayHello 方法sayHello 方法上虽然有事务注解但是这里的事务不生效因为调用的不是的动态代理对象中的 sayHello 方法而是当前对象 this 的 sayHello 方法。 2. 异常被捕获
如果我们在 sayHello 方法中将异常捕获了那么动态代理类中的方法就感知不知道目标方法发生异常了自然也就不会自动处理事务回滚了。还是以前面的 UserServiceProxy 为例
public class UserServiceProxy extends UserService{public void sayHello(){try{//开启事务//调用父类 sayHello//提交事务}catch(Exception e){//回滚事务}}
}如果调用调用父类 sayHello的时候sayHello 方法自动将异常捕获了那么很明显这里就不会进行异常回滚了。
3. 方法非 public
这个算是 Spring 官方的一个强制要求了声明式事务方法只能是 public对于非 public 的方法如果想用声明式事务那得上 AspectJ。
4. 非运行时异常
这个前面 5.3 小节介绍过了默认情况下只会捕获 RuntimeException如果想扩大捕获范围可以自行配置。
5. 不是 Spring Bean
基于 6.1 小节的理解来看这个应该也很好懂。声明式事务主要是通过动态代理来处理事务的如果你拿到手的 UserService 对象就是原原本本的 UserService如果自己 new 了一个 UserService 就是这种情况那么事务代码在哪里没有事务处理的代码事务自然不会生效。 声明式事务的核心就是动态代理生成的那个对象没有用到那个对象事务就没戏。 6. 数据库不支持事务
这个没啥好说数据库不支持Spring 咋配都没用。
总结
Spring 事务常以注解实现但存在多种可能导致失效的情况。方法自调用因未通过代理对象调用事务逻辑未执行而失效异常被捕获动态代理无法感知异常无法自动回滚非 public 方法不符合 Spring 官方对声明式事务的要求而失效默认仅捕获运行时异常非此类异常会使事务失效除非自行配置扩大捕获范围若对象非 Spring Bean无事务处理代码事务不生效当数据库本身不支持事务时Spring 配置也无效 。