当前位置: 首页 > news >正文

spring-- 事务失效原因及多线程事务失效解决方案

事务失效原因

  • 类的自调用:直接调用本类的方法,没有通过代理对象来调用方法,代理对象内部的事务拦截器不会拦截到这次行为。则不可能开启事务

  • 使用私有方法:因为spring的事务管理是基于AOP实现的,AOP代理无法拦截目标对象内部的私有方法调用。直接没有代理对象

  • 使用多线程:在主线程中开启的事务不会自动传播到其创建并执行的子线程中,则会失效

  • 如果事务回滚,将报错代码用try catch来进行捕获,事务就不会失效

  • 其他比如定义事务属性传播性时定义的是REQUIRES_NEW(脱离当前事务),事务也不会受到影响

声明式事务的底层原理:

  • 当目标类被spring管理时(即@Component,@Service,@controller,@Repository注解时),spring会为目标对象创建一个代理对象。代理对象负责拦截目标方法的调用,并在必要时应用事务管理(AOP思想)

  • 代理对象内部包含一个事务拦截器TransactionInterceptor,负责处理事务相关的逻辑

  • 事务拦截器会检查方法上是否添加了@Transactional注解,来决定是否应用事务(JDBC的connection调用setAutoCommit(false),然后会将connection存到ThreadLocal(本地线程)中,

    为了嵌套方法可以拿到外层事务的connection对象,只有使用同一个connection对象才能保证使用同一个事物)

    然后去执行方法,从而执行数据库操作,然后再执行嵌套方法,然后再嵌套方法的代理对象,就可以拿到外层事务的Thread Local中connection对象,从而执行方法,嵌套方法发现ThreadLocal中有值,他不会提交事务,而是统一的交给外层事务进行提交)

  • 事务拦截器在目标方法执行前后应用事务通知,(前置通知和后置通知)在方法执行前,事务拦截器启动事务;在方法执行后,根据方法的执行结果决定事务的提交或回滚

如下图所示:

多线程事务失效原因

如果在方法中开启新线程去调用嵌套方法时,这时嵌套线程就拿不到外层事务的ThreadLocal中的connection对象。

因为ThreadLocal是绑定在主线程上的。

所以在新的线程中去调用嵌套方法时,就拿不到外层事务的connection对象,

然后就会自己新建一个事务,自己存一个connection到自己的ThreadLocal中,

这样的话,方法和嵌套方法就各开启了一个事务,且是同级事务,相互不影响。

但是这样在外层事务失败回滚的时候,内层事务不受外层事务的影响,不进行回滚的话,就会造成事务回滚但还是写入数据库中的现象,我们要保证数据库数据的一致性!

解决方法

在创建一个异步线程之后,可以手动的往嵌套方法的Tread Local中将外层事务connection对象存入,那么嵌套方法就可以从自己的Thread Local中拿到外层事务的connection了,这样方法和嵌套方法用的就是同一个事务了。这样就不会出现多线程事务失效的情况了

前置知识:

编程式事务中DataSourceTransactionManager类org.springframework.jdbc.datasource.DataSourceTransactionManager中的doBegin方法就是spring底层在开启事务的时候进行调用的,在方法中获取数据库连接,并开启事务

所以如果想要获取对应的connection,需要调用事务同步管理器的getResource()方法,

然后将spring容器当中的datasource传进来,就可以拿到,

然后再调用BindResource方法就可以将异步线程中的ThreadLocal中存入外层事务的connection

解决方案代码展示:

 private DataSource datasource;ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizedManager.getResource(dataSource);new Thread(()->{//绑定主线程的connection到子线程中TransactionSynchronizedManager.bindResource(dataSource,connectionHolder);//调用方法})

这样便可以解决spring事务失效的情况,希望对大家有所帮助!

相关文章:

  • Flutter——数据库Drift开发详细教程(二)
  • Flutter AppBar 详解
  • “会话技术”——Cookie_(2/2)原理与使用细节
  • 【二叉树】java源码实现
  • 中小企业MES系统概要设计
  • 数字智慧方案6213丨智慧园区规划方案(63页PPT)(文末有下载方式)
  • 【学习笔记】第十章:序列建模:递归神经网络(RNN)
  • Python 数据智能实战 (8):基于LLM的个性化营销文案
  • Redis总结及设置营业状态案例
  • 分发饼干之 双数组匹配问题 (双指针 or 二分)
  • 【质量管理】现代TRIZ中问题识别中的功能分析——相互接触分析
  • 【算法题】荷兰国旗问题[力扣75题颜色分类] - JAVA
  • Rust 学习笔记:关于枚举与模式匹配的练习题
  • 从0搭建Transformer
  • 大学之大:瑞典皇家理工学院2025.5.2
  • 纯原生Java实现:获取整个项目中指定接口所有的实现类
  • 柔性超声耦合剂的选择与设计-可穿戴式柔性超声耦合剂面临的难题
  • [面试]SoC验证工程师面试常见问题(三)
  • 冯·诺依曼体系:现代计算机的底层逻辑与百年传承
  • 深度学习框架PyTorch——从入门到精通(YouTube系列 - 4)——使用PyTorch构建模型
  • 结束北京队与总决赛十年之痒的,为何会是一度被群嘲的许利民
  • 以色列消防部门:已控制住耶路撒冷山火
  • 巴菲特股东大会前瞻:执掌伯克希尔60年,巨轮将驶向何方
  • 特朗普称加总理将很快访美,白宫:不影响将加拿大打造成“第51个州”计划
  • 王受文已任中华全国工商业联合会领导班子成员
  • 南京106亿元成交19宗涉宅地块:建邺区地块楼面单价重回4.5万元