【Spring事务】Spring事务注解 @Transactional 完整体系:从 MySQL 隔离级别到 MyBatis 原理详解
作者大家好我是 CodeStats。一个在底层技术上“考古”了四年的硬核爱好者也是 WWAIC全周项目AI编程范式的提出者和实践者。我曾手写过一个完整的 Java Web 框架从 IoC 容器到嵌入式 Tomcat代码全开源也喜欢用通俗的语言拆解 CPU、JVM、操作系统的运行本质。我的技术信条所有高深的技术最后都能用大白话讲清楚。如果讲不清楚说明还没真正理解。一、本文你将获得什么通过本文我将用“层层递进”的方式带你系统掌握 Spring 声明式事务的底层全貌MySQL事务隔离级别四种隔离级别的区别与底层实现MVCC 与锁Transactional 九个参数每个参数的作用、默认值与生产环境建议超时时间timeout到底什么时候抛异常应用层还是数据库层“加入”与“挂起”深入线程上下文彻底理解事务传播的本质MyBatis 两阶段注册 BeanSqlSessionFactory 和 MapperFactoryBean 的类结构体与职责Service 层控制 MyBatis 事务注解在 Service代理在 Mapper中间只隔着一个 ThreadLocal二、正文层层递进问题一MySQL事务四种隔离级别区别是什么本章核心总结隔离级别就是数据库在“性能”和“数据一致性”之间做权衡的四档开关。2.1.1 为什么要隔离多个事务并发执行时如果不加任何控制会出现三类数据异常异常类型表现本质脏读读到其他事务未提交的数据信任了不该信任的中间状态不可重复读同一事务两次读同一行结果不同数据被其他已提交事务修改了幻读同一事务两次范围查询记录数不同其他事务插入了新数据2.1.2 MySQL 四种隔离级别隔离级别脏读不可重复读幻读MySQL 实现方式READ UNCOMMITTED✅ 可能✅ 可能✅ 可能不加锁直接读最新版本READ COMMITTED❌✅ 可能✅ 可能MVCC每次读生成新视图REPEATABLE READ默认❌❌❌ 理论上可能MySQL 通过 MVCC 解决MVCC事务开始生成视图 间隙锁SERIALIZABLE❌❌❌读加共享锁S锁写加排他锁X锁面试追问MySQL 默认 REPEATABLE READ为什么 Oracle 默认 READ COMMITTED因为 MySQL 通过 MVCC 间隙锁在 RR 下解决了幻读但代价是更高的锁开销Oracle 的 RR 不解决幻读通过序列号快照本质上更接近 MySQL 的 RC。2.1.3 Spring 隔离级别枚举javapublic enum Isolation { DEFAULT, // 随数据库MySQLREPEATABLE_READOracleREAD_COMMITTED READ_UNCOMMITTED, READ_COMMITTED, // 生产最推荐避免脏读且性能优秀 REPEATABLE_READ, SERIALIZABLE }问题二Spring的 Transactional 注解九个参数分别什么作用本章核心总结九大参数本质是开发者在方法上贴的一张“事务执行命令清单”告诉 Spring“怎么开、怎么关、什么情况算失败”。2.2.1 参数全览参数类型默认值一句话作用value / transactionManagerString多数据源时指定用哪个事务管理器propagationPropagationREQUIRED有事务就加入没事务就新建isolationIsolationDEFAULT使用数据库默认隔离级别timeoutint秒-1无限事务最多跑多久超时就抛异常timeoutStringString-timeout 的字符串版readOnlybooleanfalse是否为只读事务优化 flushrollbackForClass[]{}哪些异常必须回滚rollbackForClassNameString[]{}同上用类名字符串noRollbackForClass[]{}哪些异常不回滚2.2.2 核心参数详解1propagation —— 7种传播行为面试高频传播行为有事务时的行为无事务时的行为经典场景REQUIRED默认加入新建增删改业务SUPPORTS加入非事务执行查询操作有也行没有更快MANDATORY加入抛异常强制要求在事务中执行REQUIRES_NEW挂起外部新建独立事务新建操作日志必须独立提交NOT_SUPPORTED挂起外部非事务执行非事务执行执行不重要的清理脚本NEVER抛异常非事务执行绝对禁止事务的场景NESTED在当前事务中创建保存点新建同REQUIRED局部回滚外部统一提交2rollbackFor —— 最关键的生产配置java// 生产环境推荐只要抛异常就回滚不管是不是RuntimeException Transactional(rollbackFor Exception.class) public void transfer() { ... }原因Spring 默认只对RuntimeException和Error回滚对SQLException、IOException等checked 异常不回滚。不写rollbackFor Exception.class数据库报错可能就悄悄吞掉了。问题三Transactional 超时时间是到时间就抛异常还是执行时检查是应用层还是数据库超时本章核心总结Transactional 的超时是“执行时检查”而非“定时炸弹”它只在数据库操作前看一眼秒表超时就报错。2.3.1 检查机制执行时检查非后台轮询答案是执行时检查。Spring 不会启动一个后台线程每秒钟去扫描超时事务而是在数据库操作执行前进行“按需检查”。检查点有三个每次获取数据库连接时最核心DataSourceUtils.getConnection()内部会检查ConnectionHolder.isTimeout()。事务提交/回滚时兜底检查防止纯逻辑执行太久。事务开始时启动一个定时任务仅用于标记超时状态配合检查点使用。2.3.2 超时计时范围Spring 事务超时 事务开始时间 到 所有数据库操作执行完成的时间。致命陷阱如果方法里有Thread.sleep(15000)纯 Java 逻辑且 timeout10不会触发超时。因为 Spring 只有在执行 SQL 时才去检查秒表sleep期间没有数据库操作不触发检查。2.3.3 应用层超时 vs 数据库超时层级实现类作用范围抛出异常应用层SpringConnectionHolder.timeout整个事务方法内的所有SQLTransactionTimedOutException数据库层JDBCStatement.setQueryTimeout()单条 SQL 语句的执行时间SQLTimeoutException两者是独立的Spring 超时到时间了会在下一次数据库操作前抛TransactionTimedOutException。数据库超时是单条 SQL 执行太久被数据库 kill 掉。问题四Transactional“加入”和“挂起”是什么意思本章核心总结“加入”就是共享同一根数据库连接“挂起”就是先把旧连接寄存起来腾出手来干自己的事。2.4.1 “加入”Join—— 共享同一连接当前线程的ThreadLocal实际是TransactionSynchronizationManager里已经有绑定的连接时新方法直接取出来用不新建。java// 加入的本质直接复用 Connection existing TransactionSynchronizationManager.getResource(dataSource); if (existing ! null) { // 这就是加入直接使用现有连接共用一个事务上下文 return existing; }后果所有加入的方法共享同一个物理连接最终一起commit或一起rollback。2.4.2 “挂起”Suspend—— 寄存旧连接换新连接当传播行为是REQUIRES_NEW或NOT_SUPPORTED时Spring 执行挂起java// 挂起的本质存旧换新 Connection old TransactionSynchronizationManager.unbindResource(dataSource); // 取出并解绑 suspendedResources old; // 存到栈里 Connection newConn dataSource.getConnection(); // 建立新连接 bindResource(dataSource, newConn); // 绑定新连接 // ... 执行内部方法 ... // 内部方法结束后恢复旧连接 bindResource(dataSource, old);后果内外两个事务完全独立内部提交/回滚不影响外部。2.4.3 REQUIRES_NEW vs NESTED终极对比维度REQUIRES_NEWNESTED连接数2个挂起旧新建新1个复用旧内部回滚内部回滚后立即提交如果成功回滚到 Savepoint不提交外部回滚不影响内部已独立提交内部一起被回滚本质两个独立物理事务一个物理事务 一个逻辑保存点问题五MyBatis 两阶段注册 Bean 完整类结构体——SqlSessionFactory 和 MapperFactoryBean 作用本章核心总结MyBatis 启动阶段就是两件事——把 SQL 编译成“蓝图”MappedStatement把 Mapper 接口包装成“工厂”MapperFactoryBean。2.5.1 第一阶段启动注册IoC 容器构建Spring Boot 启动时MybatisAutoConfiguration负责向容器注册两个核心 Beantext【阶段一BeanDefinition 注册】 1. MybatisAutoConfiguration 被 Conditional 条件触发 2. 创建 SqlSessionFactoryBean这是一个 FactoryBean └── 解析 mybatis-config.xml 和所有 Mapper.xml └── 生成 Configuration 对象内含所有 MappedStatement 3. 通过 MapperScan 扫描所有 Mapper 接口 └── 为每个 Mapper 接口生成 MapperFactoryBean 的 BeanDefinition核心类结构体java// 1. SqlSessionFactory实际实现是 DefaultSqlSessionFactory public class DefaultSqlSessionFactory implements SqlSessionFactory { // 持有核心配置对象 private final Configuration configuration; Override public SqlSession openSession() { // 从 configuration 中取 Environment获取 DataSource // 创建 Executor 和 DefaultSqlSession } } // Configuration 内部结构第一阶段解析成果 public class Configuration { // 所有 SQL 的蓝图 protected final MapString, MappedStatement mappedStatements; // 所有注册的 Mapper 接口 protected final MapClass?, MapperRegistry mapperRegistry; // 数据源、事务工厂等 protected Environment environment; }java// 2. MapperFactoryBean为每个 Mapper 接口生成代理 public class MapperFactoryBeanT extends SqlSessionDaoSupport implements FactoryBeanT { private ClassT mapperInterface; Override public T getObject() throws Exception { // 返回动态代理对象不是 Mapper 实现类 return getSqlSession().getMapper(this.mapperInterface); } }2.5.2 第二阶段运行时调用执行 SQLtext【阶段二运行时调用链】 Service 调用 mapper.selectById() ↓ MapperProxyJDK动态代理触发 invoke() ↓ MapperMethod.execute() 根据 SQL 类型路由 ↓ SqlSessionTemplateSpring包装的 SqlSession ↓ 从 Configuration 中取出 MappedStatement蓝图 ↓ Executor 执行Simple / Reuse / Batch ↓ StatementHandler 编译 SQL 设置参数 ↓ ResultSetHandler 映射结果问题六Service 层的 Transactional 如何控制 MyBatis 的事务本章核心总结Service 层通过 ThreadLocal 这个“线程公共储物柜”把连接交给 Mapper实现事务的隔空控制。2.6.1 核心答案隔空传物ThreadLocalService 和 Mapper 之间没有任何直接引用关系。Service 的代理把连接放进当前线程的ThreadLocal仓库Mapper 执行时主动去这个仓库里拿。2.6.2 完整调用链路含源码级原理步骤执行主体具体动作对 ThreadLocal 做了什么①TransactionInterceptorAOP代理进入 Service 方法前从 DataSource 获取物理连接执行setAutoCommit(false)存入TransactionSynchronizationManager.bindResource(dataSource, connection)②UserService真实业务对象执行orderDao.insert()无感不关心连接③MapperProxyJDK代理触发invoke()委托给SqlSessionTemplate无感④SqlSessionTemplate内部拦截器调用DataSourceUtils.getConnection(dataSource)取出从TransactionSynchronizationManager.getResource(dataSource)取出第①步放入的连接⑤Executor用取出的连接执行 JDBC 操作无感⑥TransactionInterceptor后置方法返回后根据是否抛异常执行commit()或rollback()移除TransactionSynchronizationManager.unbindResource(dataSource)2.6.3 为什么必须把 Transactional 加在 Service 层如果加在 Mapper 层每次调用userMapper.insert()就开启一个独立事务执行完立即提交。Service 里三个 Mapper 操作下单、扣库存、扣余额就是三个独立事务。第三个报错时前两个已经提交了无法回滚数据产生不一致。如果加在 Service 层整个 Service 方法是一个事务边界。所有 Mapper 操作共享同一个连接一起提交或一起回滚。保证业务原子性。2.6.4 Spring MyBatis 整合的连接获取源码级逻辑java// SqlSessionTemplate 内部获取连接的核心逻辑简化 public Connection getConnection(DataSource dataSource) { // 1. 先去当前线程的 ThreadLocal 里找事务管理器放连接的地方 ConnectionHolder holder TransactionSynchronizationManager.getResource(dataSource); if (holder ! null holder.hasConnection()) { // 2. 找到了说明当前方法被 Transactional 包裹 // 直接返回这个已经开启事务的连接这就是“加入”当前事务 return holder.getConnection(); } else { // 3. 没找到说明没有事务 // 直接从数据源 new 一个物理连接非事务场景用完立即关闭 return dataSource.getConnection(); } }三、全文内容总结层层递进的逻辑链条我们把六个问题串起来形成一条完整的技术认知链层级核心问题核心结论数据库层问题一MySQL 隔离级别怎么选隔离级别是“性能”与“一致性”的四档开关READ_COMMITTED是生产最佳平衡点。Spring API 层问题二九个参数怎么配九大参数是贴在方法上的“事务执行命令清单”rollbackForException.class是必加项。Spring 内部机制问题三、四超时和传播怎么实现超时是“执行时检查”而非定时炸弹加入/挂起本质是 ThreadLocal 中连接的“共享”与“寄存”。MyBatis 整合层问题五MyBatis 怎么注册到 Spring启动阶段把 SQL 编译成MappedStatement蓝图把 Mapper 包装成MapperFactoryBean工厂。运行时线程层问题六Service 怎么控制 Mapper通过TransactionSynchronizationManagerThreadLocal 仓库完成连接的隔空传递与边界控制。终极结论Spring 事务的本质从来不是代码块嵌套而是数据库连接Connection在不同层级之间有序流转与边界控制。理解了ThreadLocal这个“线程公共储物柜”你就理解了 Spring 事务、MyBatis 整合、乃至整个 Java Web 声明式治理的底层灵魂。四、最后如果这篇从数据库隔离级别一路“考古”到 ThreadLocal 底层流转的文章对你有帮助欢迎点赞 —— 让更多朋友看到硬核内容收藏⭐ —— 随时回顾 Spring MyBatis 事务全链路关注 —— 下次我讲“手写 Spring 事务管理器实现”时第一时间收到有任何疑问欢迎评论区交流我会从源码层面一一回复。

相关新闻

智慧职教刷课脚本:三步轻松实现自动化学习

智慧职教刷课脚本:三步轻松实现自动化学习

智慧职教刷课脚本:三步轻松实现自动化学习 【免费下载链接】auto-play-course 简单好用的刷课脚本[支持平台:职教云,智慧职教,资源库] 项目地址: https://gitcode.com/gh_mirrors/hc/auto-play-course 智慧职教刷课脚本是一款专为职业教育学生设计的智能自动…

2026/7/26 18:31:15阅读更多 →
【Springboot毕设全套源码+文档】基于springboot竞赛团队组建与管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

【Springboot毕设全套源码+文档】基于springboot竞赛团队组建与管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/26 18:31:15阅读更多 →
【Springboot毕设全套源码+文档】基于SpringBoot+Vue的在线商场后台管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

【Springboot毕设全套源码+文档】基于SpringBoot+Vue的在线商场后台管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/26 18:31:15阅读更多 →
人工智能训练师三级全真模拟试卷(一)|65题+答案解析 2026版

人工智能训练师三级全真模拟试卷(一)|65题+答案解析 2026版

摘要:人工智能训练师三级全真模拟试卷(一):65题(单选30+多选10+判断15+简答10),附完整答案解析。严格按照考试大纲设计,题型分布、难度比例、考点覆盖均参考历年真题规律,附AutoGrader自动评分工具和薄弱点分析报告。 一、导读 本试卷严格按照三级人工智能训练师考试…

2026/7/26 23:06:14阅读更多 →
人工智能训练师三级全真模拟试卷(二)|65题+答案解析+新考点覆盖 2026版

人工智能训练师三级全真模拟试卷(二)|65题+答案解析+新考点覆盖 2026版

摘要:人工智能训练师三级全真模拟试卷(二):65题(单选30+多选10+判断15+简答10),与卷一内容完全不重复,覆盖更多新考点。侧重概念辨析、流程规范、工具使用和最佳实践判断,附AutoGrader自动评分工具。 一、导读 本套试卷为第二套模拟试卷,内容与卷一完全不重复,覆盖…

2026/7/26 23:06:14阅读更多 →
人工智能训练师三级全真模拟试卷(三)|65题+MLOps+Prompt工程+答案解析

人工智能训练师三级全真模拟试卷(三)|65题+MLOps+Prompt工程+答案解析

摘要:人工智能训练师三级全真模拟试卷(三):65题(单选30+多选10+判断15+简答10),重点覆盖MLOps基础、模型测试方法论、Prompt工程、生产环境监控等前沿考点。简答题难度略高,侧重综合场景分析,适合拔高训练。 一、导读 第三套模拟试卷在题型结构一致的基础上,重点覆盖…

2026/7/26 23:06:14阅读更多 →
ANA-GIA模型参数操纵技术与优化实践

ANA-GIA模型参数操纵技术与优化实践

1. ANA-GIA模型参数操纵技术解析 在机器学习模型优化领域,参数操纵一直是提升模型性能的关键手段。最近在业内交流中发现,ANA-GIA模型通过独特的参数调整策略,在多个基准测试中取得了显著效果提升。这种参数操纵方法不同于常规的超参数调优&a…

2026/7/26 23:06:14阅读更多 →
二维码生成优化:从基础原理到高识别率的技术实践

二维码生成优化:从基础原理到高识别率的技术实践

最近在开发一个需要生成二维码的项目时,我发现了一个很有意思的问题:明明按照标准流程生成了二维码,但某些扫码设备就是识别不出来。经过一番排查,发现问题出在二维码的"最后一杀"——那些看似不起眼的细节上。二维码技…

2026/7/26 23:06:14阅读更多 →
UE5对话系统开发指南:从数据驱动到高级集成的完整实现方案

UE5对话系统开发指南:从数据驱动到高级集成的完整实现方案

1. 项目概述:为什么UE5对话系统值得投入在UE5里折腾对话系统,这事儿我干过不止一次。从最早的简单文本气泡,到后来带分支选择、表情动画、语音同步的复杂叙事,踩过的坑能写满一张A4纸。很多刚接触UE5的朋友,尤其是从独…

2026/7/26 23:04:14阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/26 0:01:28阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/26 0:01:28阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/26 0:01:28阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/26 0:01:28阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/26 0:01:28阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/26 0:01:28阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/25 23:03:25阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/26 19:05:21阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/26 19:05:21阅读更多 →