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

接口添加了 @Transactional 注解并开启事务,而其中一个小方法启动了新线程并手动提交数据,会有什么影响?

多线程环境下的事务处理分析

大方法添加了 @Transactional 注解并开启事务,而其中一个小方法启动了新线程并手动提交数据,这种设计会带来特殊的事务行为:

问题分析

  1. 大方法报错能否回滚数据?

    • 大方法中的操作(在原始线程中执行的)可以正常回滚
    • 新线程中已提交的数据不会被回滚
  2. 新线程手动提交的影响范围:

    • 新线程中手动提交的数据只会影响该线程自己的操作
    • 不会影响大方法所在线程的事务

原因说明

事务边界与线程关系

大方法开始
主线程事务开启
小方法1
小方法2
启动新线程
新线程事务开启
手动提交数据
大方法报错
主线程事务回滚
新线程事务提交
  1. Spring事务基于ThreadLocal

    • 事务上下文绑定在当前线程
    • 新线程不会继承原线程的事务上下文
  2. 手动提交的独立性

    • 新线程中手动提交会创建独立的事务
    • 提交后数据立即持久化到数据库
  3. 大方法回滚范围

    • 只能回滚原始线程中的操作
    • 无法影响已在新线程提交的数据

示例代码说明

@Service
public class TransactionService {@Autowiredprivate DataSource dataSource;@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)public void bigMethod() {// 主线程操作1jdbcTemplate.update("INSERT INTO main_table1 VALUES (...)");// 启动新线程执行独立操作startNewThreadOperation();// 主线程操作2jdbcTemplate.update("INSERT INTO main_table2 VALUES (...)");// 模拟报错(此异常将触发主事务回滚)throw new RuntimeException("Big method error");}private void startNewThreadOperation() {new Thread(() -> {// 获取独立连接(不与主事务共享)try (Connection conn = dataSource.getConnection()) {conn.setAutoCommit(false); // 开启事务// 新线程操作try (Statement stmt = conn.createStatement()) {stmt.executeUpdate("INSERT INTO thread_table VALUES (...)");conn.commit(); // 手动提交}} catch (SQLException e) {// 处理异常}}).start();}
}

执行结果

操作位置数据表是否提交是否受回滚影响
大方法 - 操作1main_table1未提交回滚
新线程thread_table已提交不受影响
大方法 - 操作2main_table2未提交回滚

解决方案建议

如果希望新线程操作也能参与大事务的回滚,考虑以下方案:

方案1:使用事务同步器(推荐)

@Transactional
public void bigMethod() {// 主线程操作...// 注册事务完成后的回调TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {@Overridepublic void afterCommit() {// 主事务成功后执行executeInNewThread();}});// ...其他操作
}

方案2:使用异步事务

@Transactional
public void bigMethod() {// 主线程操作...// 异步执行(使用REQUIRES_NEW传播)asyncService.executeInNewTransaction();// ...其他操作
}@Service
public class AsyncService {@Async@Transactional(propagation = Propagation.REQUIRES_NEW)public void executeInNewTransaction() {// 新事务中执行}
}

方案3:统一事务管理

public void bigMethod() {TransactionTemplate template = new TransactionTemplate(transactionManager);template.execute(status -> {// 所有操作在同一个事务中mainOperation1();mainOperation2();// 在新线程执行但使用相同事务(不推荐,复杂)executeInSameTransactionThread();return null;});
}

关键结论

  1. 新线程提交的数据不受主事务回滚影响:因为已创建独立事务并提交
  2. 主线程事务可以正常回滚:只影响未提交的主线程操作
  3. 设计建议
    • 避免在事务方法内启动线程执行数据库操作
    • 如需后台处理,使用事务完成后的回调机制
    • 考虑使用消息队列解耦耗时操作

这种设计打破了事务的原子性,需要根据业务需求仔细评估数据一致性的要求。

http://www.lryc.cn/news/620118.html

相关文章:

  • 服务器安全笔记
  • 学习:JS进阶[10]内置构造函数
  • [ 数据结构 ] 泛型 (上)
  • Excel多级数据结构导入导出工具
  • Laravel 使用ssh链接远程数据库
  • Linux Framebuffer(帧缓冲)与基本 UI 绘制技术
  • 【R语言】RStudio 中的 Source on Save、Run、Source 辨析
  • 认知系统的架构: 认知残余三角形、认知主体意识 和认知演进金字塔
  • 【docker①】在VS Code中使用Docker容器
  • 从零用 NumPy 实现单层 Transformer 解码器(Decoder-Only)
  • 未来AI:微算法科技(NASDAQ:MLGO)开发基于忆阻器网络储层计算MemristorPattern虚拟平台
  • 通过限制网络访问来降低服务器被攻击风险的方法
  • 云原生技术k8s部署prometheus
  • 面向Python/C#开发者入门Java与Bukkit API
  • C# 反射和特性(元数据和反射)
  • Mysql——如何做到Redolog崩溃后恢复的
  • NLP学习之Transformer(1)
  • 算法题——哈希表
  • 洛谷 P2607 [ZJOI2008] 骑士-提高+/省选-
  • 从 Web 开发到数据科学:全栈基础技术总结
  • nm命令和nm -D命令参数
  • 互联网大厂Java求职面试实录:Spring Boot到微服务与AI的技术问答
  • 《量子雷达》第2章 从量子信息到量子雷达 预习2025.8.13
  • Canal解析MySQL Binlog原理与应用
  • RC4算法实现
  • 一键自动化:Kickstart无人值守安装指南
  • 如何优雅地实现API接口每 10秒轮询请求?
  • 力扣面试150题--三角形最小路径和 最小路径和 不同路径 最长回文子串
  • RagFlow启动源码说明
  • 前后端分离项目在云服务器的部署