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

【Java】Spring的声明事务在多线程场景中失效问题。

大家都知道Spring的声明式事务在多线程当中会失效,来看一下如下案例。
按照如下方式,b()方法抛出异常,由于父子线程导致事务失效,a()会成功插入,但是b()不会。
因此成功插入一条数据,事务失效。

@Component
public class UserServiceImpl implements UserService{@Transactionalpublic void a(){jdbcTemplate.execute("insert into `user`(`age`,`name`,`city`) values(18,'张三','北京')");UserService userService = (UserService)AopContext.currentProxy();Thread thread = new Thread(()->{userService.b();})}@Transactionalpublic void b(){jdbcTemplate.execute("insert into `user`(`age`,`name`,`city`) values(19,'张三','北京')");throw new RuntimeException();}}

这里就需要了解一下嵌套方法事务的传播行为是怎么实现的?
在这里插入图片描述
如图所示,如果b()方法是在子线程当中的,因为ThreadLocal不是同一个因此子线程又创建了一个事务。由于是各用各的事务所以事务b就会回滚,而事务a的数据就会插入成功。
要保证这种父子线程中的事务传播,则在创建子线程后把父线程中的事务取出来再设置进去。
进行如下改造后保证两个线程使用同一个事务。
在这里插入图片描述
那么接下来的问题就是如何获取外层的connection以及如何设置到子线程的ThreadLocal中。
这里就需要看一下源码了
需要看这个类org.springframework.jdbc.datasource.DataSourceTransactionManager找到doBegin()方法

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {Connection newCon = obtainDataSource().getConnection();if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con = txObject.getConnectionHolder().getConnection();Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);txObject.setReadOnly(definition.isReadOnly());if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}// 这里开启事务con.setAutoCommit(false);}prepareTransactionalConnection(con, definition);txObject.getConnectionHolder().setTransactionActive(true);int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 这里将连接存入到ThreadLocalif (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, obtainDataSource());txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}
}

最终改造

@Component
public class UserServiceImpl implements UserService{@Transactionalpublic void a(){ConnectionHolder connectionHolder = TransactionSynchronizationManager.getResource(dataSource);jdbcTemplate.execute("insert into `user`(`age`,`name`,`city`) values(18,'张三','北京')");UserService userService = (UserService)AopContext.currentProxy();Thread thread = new Thread(()->{// 绑定主线程的connection到子线程TransactionSynchronizationManager.bindResource(dataSource,connectionHolder);userService.b();})}@Transactionalpublic void b(){jdbcTemplate.execute("insert into `user`(`age`,`name`,`city`) values(19,'张三','北京')");throw new RuntimeException();}}
http://www.xdnf.cn/news/470197.html

相关文章:

  • 以项目的方式学QT开发(二)——超详细讲解(120000多字详细讲解,涵盖qt大量知识)逐步更新!
  • ​​STC51系列单片机引脚分类与功能速查表(以STC89C52为例)​
  • 合并两个有序数组的高效算法详解
  • 多级分类的实现方式
  • Xinference推理框架
  • 遗传算法求解旅行商问题分析
  • Python内存管理:赋值、浅拷贝与深拷贝解析
  • Mendix 连接 MySQL 数据库
  • Linux动态库热加载驱动插件机制-示例
  • 国标GB28181视频平台EasyGBS助力智慧医院打造全方位视频监控联网服务体系
  • QML元素 - MaskedBlur
  • 力扣-236.二叉树的最近公共祖先
  • Elasticsearch 常用语法手册
  • 格恩朗椭圆齿轮流量计 工业流量测量的可靠之钥
  • MySQL库的操作
  • 【笔记】CosyVoice 模型下载小记:简单易懂的两种方法对比
  • vacuum、vacuum full的使用方法及注意事项
  • “禁塑行动·我先行”环保公益项目落地宁夏,共筑绿色生活新篇章
  • 4、前后端联调文生文、文生图事件
  • 趋势跟踪策略的回测
  • AI Agent开发第67课-彻底消除RAG知识库幻觉-文档分块全技巧(1)
  • pgsql14自动创建表分区
  • SpringBoot 自动装配流程
  • [Java实战]Spring Boot 3实现 RBAC 权限控制(二十五)
  • SpringBoot项目使用POI-TL动态生成Word文档
  • 去年开发一款鸿蒙Next Os的window工具箱
  • 软考软件评测师——软件工程之系统维护
  • ADS1220高精度ADC(TI)——应用 源码
  • 采用sherpa-onnx 实现 ios语音唤起的调研
  • 每周靶点:NY-ESO-1、GPC3、IL27分享