本系列帖子为鼠鼠复习八股巩固记忆和个人理解所写,如有错误纯属本人实力不佳,欢迎各位大佬阅读指正
1.Spring的事务什么情况下会失效?
底层原理:@Transaction事务依靠AOP动态代理实现,方法调用必须经过代理对象,增强逻辑(开启/提交/回滚事务)才能执行。
同类内部方法自调用
在同一个Service中,使用this.xxx()调用本类带有@Transactional的方法,this指向原生目标对象,绕过代理对象,事务通知无法执行,事务失效。
事务方法非public修饰
private、protected、默认访问权限的方法添加@Transactionl失效,CGLIB动态代理生成子类,无法重写非public方法,不能完成增强。(static,final修饰的方法同样无法被代理增强,事务失效)。
异常被try-catch捕获且未重新抛出
事务拦截器依靠捕获方法抛出的异常判断是否回滚,异常被捕获吃掉,没有向外抛出,代理感知不到异常,不会触发回滚,同时Spring事务默认只对RuntimeException、Error触发回滚,普通受检异常不回滚,需要动手配置。
事务传播行为配置不当
例如:Propagation.SUPPORTS外层不存在事务时,当前方法以非事务方式运行。
Propagation.NOT_SUPPORTED强制挂起已有事务,使用非事务执行,配置错误会表现出事务不生效。
数据库存储引擎不支持事务
如MySQL使用MyISAM引擎,本身不支持事务,无论注释如何配置都无效,需要更换为InnoDB。
跨线程执行数据库操作
Spring事务信息存放在ThreadLocal,事务上下文绑定当前线程。
新开子线程执行DB操作,子线程拥有独立连接,无法加入主线程事务,不能统一回滚。
@Transaction仅标注在接口方法上
使用JDK动态代理场景下存在识别风险,规范需要将注解加在实现类public方法上。
2.Spring的事务,使用this调用是否生效?
不生效,Spring的@Transaction声明事务底层依靠AOP动态代理实现,事务的创建、提交、回滚逻辑全部写在代理对象的增强逻辑中,在同一个类内部使用this方法调用带有@Transaction的方法,this代表原始目标对象,不是Spring生成的代理对象,方法调用不会经过AOP拦截器,事务增强逻辑不会执行,事务失效。
追问:this 内部调用事务失效,有哪些解决方案?
this指向原生对象,不走AOP代理,事务增强逻辑无法执行。
三种解决方案:
自行注入,使用self.方法调用,self是容器中的代理对象
将带有事务的方法抽取到另外一个Service,跨类调用
通过AopContext.currentProxy()获取代理对象,必须额外开启配置。