ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

《Java 100 天进阶之路》第76篇:Spring事务(2026版)

《Java 100 天进阶之路》第76篇:Spring事务(2026版) 第76篇Spring事务2026精版系列导航《Java 100 天进阶之路》完整目录 |⬅️ 上一篇第75篇Spring AOP原理 |➡️ 下一篇第77篇Spring MVC流程️ 本文阅读地图3 分钟速览第75篇搞定了AOP原理本篇深入Spring事务管理。Transactional是Java后端每天都要用的注解但很多人加了注解就以为万事大吉——事务不生效、传播行为配错、隔离级别选错线上出了数据不一致才追悔莫及。搞懂Spring事务就是搞懂了数据一致性的最后一道防线模块核心问题一句话回答事务是什么为什么需要事务一组数据库操作要么全成功要么全失败——经典场景就是银行转账ACID特性事务的四大特性是什么原子性、一致性、隔离性、持久性——其中一致性是最终目标编程式 vs 声明式两种事务管理方式怎么选编程式手动调API灵活但耦合声明式加Transactional推荐零侵入Transactional原理一个注解怎么搞定事务基于AOP动态代理在方法执行前后自动开启、提交/回滚事务隔离级别事务隔离级别解决什么问题解决脏读、不可重复读、幻读三大并发问题传播行为事务方法调用事务方法怎么办7种传播行为定义事务边界——REQUIRED默认、REQUIRES_NEW、NESTED等失效场景Transactional为什么不生效自调用、非public、异常被吞、final方法……12种失效场景面试最爱问高频考点有哪些见文末 小节一、核心知识点1. 事务是什么事务Transaction是一组原子性的SQL操作这组操作要么全部执行成功要么全部执行失败不会出现部分成功部分失败的情况。最经典的例子就是银行转账A向B转账100元包含两个步骤——A的账户余额减少100元B的账户余额增加100元。如果没有事务A扣钱成功但B加钱失败钱就凭空消失了。2. ACID四大特性事务必须满足ACID四大特性特性核心含义数据库实现机制原子性Atomicity事务是不可分割的整体要么全执行要么全回滚Undo Log回滚日志一致性Consistency事务执行前后数据完整性约束不被破坏由原子性、隔离性、持久性共同保证隔离性Isolation多个并发事务之间相互隔离、互不干扰锁机制 MVCC持久性Durability事务一旦提交修改永久生效Redo Log重做日志 WAL关键区分原子性关注事务内操作的整体性一致性关注数据库状态的正确性隔离性关注并发事务间的互不干扰持久性关注数据的永久保存。3. 为什么需要Spring事务原生JDBC需要手动管理事务——setAutoCommit(false)、commit()、rollback()每个需要事务的方法都要写一遍模板代码。Spring事务通过Transactional一个注解搞定一切让开发者专注于业务逻辑。二、通俗讲解1分钟开心学把事务想象成银行柜员的操作日志原子性柜员处理一笔转账要么把A扣钱和B加钱都做完要么都撤销——绝不出现A扣了B没加的状态。一致性转账前后银行总金额不变——这就是数据的一致性。隔离性多个柜员同时处理不同客户的业务互不干扰——你不能看到隔壁柜员正在操作的半成品数据。持久性柜员办完业务把记录写进账本——哪怕晚上断电了第二天账本上的记录还在。把Spring事务的两种方式想象成点餐编程式事务你亲自去后厨盯着厨师做菜——“开始做”“做好了”“出问题了快停下”——累死你。声明式事务Transactional你跟服务员说我要一份宫保鸡丁——服务员自动帮你下单、盯菜、上菜——你只管吃。三、编程式事务 vs 声明式事务Spring提供了两种事务管理方式3.1 编程式事务在代码中显式调用事务APIServicepublicclassTransferService{privatefinalPlatformTransactionManagertransactionManager;publicvoidtransfer(LongfromId,LongtoId,BigDecimalamount){// 1. 定义事务属性TransactionDefinitiondefnewDefaultTransactionDefinition();// 2. 开启事务TransactionStatusstatustransactionManager.getTransaction(def);try{// 3. 执行业务逻辑accountDao.decrease(fromId,amount);accountDao.increase(toId,amount);// 4. 提交事务transactionManager.commit(status);}catch(Exceptione){// 5. 出现异常回滚事务transactionManager.rollback(status);throwe;}}}优点精细控制可以在代码的任何位置决定事务边界。缺点事务代码和业务代码混在一起每个需要事务的方法都要写一遍模板代码。3.2 声明式事务推荐通过Transactional注解声明事务边界由Spring在运行时自动管理ServicepublicclassTransferService{Transactionalpublicvoidtransfer(LongfromId,LongtoId,BigDecimalamount){accountDao.decrease(fromId,amount);accountDao.increase(toId,amount);}}优点零侵入、简洁、推荐使用。缺点最细粒度只能到方法级别无法做到代码块级别。实际项目怎么选绝大多数场景用声明式事务Transactional只有极少数需要精细化控制事务边界的场景才用编程式事务。四、Transactional 原理4.1 底层原理AOP 动态代理Transactional的底层原理是AOP 动态代理。Spring在运行时为目标Bean创建代理对象在代理对象中拦截目标方法的调用在方法执行前后自动处理事务的开启、提交和回滚。4.2 核心源码入口代理创建AbstractAutoProxyCreator事务拦截TransactionInterceptor.invoke()关键点Transactional依赖AOP代理生效。如果Bean没有被代理比如自调用、非public方法事务就不会生效。五、Transactional 核心属性Transactional注解提供了多个核心属性用于精细化控制事务行为属性作用默认值示例propagation事务传播行为Propagation.REQUIREDTransactional(propagation Propagation.REQUIRES_NEW)isolation事务隔离级别Isolation.DEFAULTTransactional(isolation Isolation.READ_COMMITTED)rollbackFor指定哪些异常触发回滚RuntimeException和ErrorTransactional(rollbackFor Exception.class)noRollbackFor指定哪些异常不触发回滚无Transactional(noRollbackFor BusinessException.class)timeout事务超时时间秒底层默认Transactional(timeout 30)readOnly是否为只读事务falseTransactional(readOnly true)5.1 rollbackFor 详解Spring事务默认只对未捕获的RuntimeException运行时异常和Error进行回滚而普通的Exception检查异常不会触发回滚。// ❌ 默认不回滚——SQLException是检查异常TransactionalpublicvoidupdateUser()throwsSQLException{// 抛出SQLException → 事务不会回滚}// ✅ 指定rollbackFor Exception.classTransactional(rollbackForException.class)publicvoidupdateUser()throwsException{// 任何异常都会触发回滚}最佳实践对于关键写操作建议加上rollbackFor Exception.class确保任何异常都能触发回滚。5.2 readOnly 详解readOnly true表示当前事务为只读事务Spring会进行优化——不开启事务的commit/rollback逻辑某些数据库如MySQL也会优化查询性能。六、事务隔离级别Isolation6.1 并发事务的三大问题隔离级别解决的是并发事务之间的相互影响问题问题定义示例脏读一个事务读取了另一个事务未提交的修改数据事务B修改了数据但未提交事务A读取到了这个脏数据不可重复读同一个事务内两次读取同一行数据结果不同事务A第一次查询id1的余额为100事务B修改并提交后事务A第二次查询变成了200幻读同一个事务内两次执行相同的范围查询结果集行数不同事务A查询age20的用户有5条事务B插入了一条age20的用户并提交事务A再查变成了6条6.2 SQL标准定义的四个隔离级别隔离级别越高并发性能越低但数据一致性越好隔离级别脏读不可重复读幻读说明READ_UNCOMMITTED读未提交✅✅✅最低级别几乎不使用READ_COMMITTED读已提交❌✅✅Oracle/SQL Server默认REPEATABLE_READ可重复读❌❌✅MySQL InnoDB默认SERIALIZABLE串行化❌❌❌最高级别强制串行执行性能极差MySQL特殊说明InnoDB引擎的REPEATABLE_READ级别通过Next-Key Lock间隙锁行锁解决了幻读问题这是MySQL对标准SQL的扩展。6.3 Spring中的隔离级别配置Spring通过Isolation枚举定义了5种隔离级别publicenumIsolation{DEFAULT(-1),// 使用数据库默认隔离级别READ_UNCOMMITTED(1),// 读未提交READ_COMMITTED(2),// 读已提交REPEATABLE_READ(4),// 可重复读SERIALIZABLE(8);// 串行化}使用方式Transactional(isolationIsolation.READ_COMMITTED)publicvoidupdateUser(){// ...}七、事务传播行为Propagation7.1 什么是传播行为传播行为定义的是当一个事务方法调用另一个事务方法时事务应该如何传递。Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。7.2 七种传播行为详解传播行为说明使用场景REQUIRED默认如果当前有事务就加入没有就新建一个大多数场景默认选择SUPPORTS有事务就加入没有就以非事务方式执行查询方法可有可无的事务MANDATORY必须存在一个事务否则抛异常强制要求调用方有事务REQUIRES_NEW无论当前有没有事务都新建一个事务独立操作不受外部事务影响NOT_SUPPORTED以非事务方式执行如果有事务则挂起不需要事务的操作NEVER以非事务方式执行如果有事务则抛异常强制不能在事务中执行NESTED如果当前有事务则在嵌套事务中执行局部回滚不影响外部事务7.3 最常用的三种对比对比REQUIREDREQUIRES_NEWNESTED事务关系加入当前事务新建独立事务嵌套在当前事务中回滚影响统一回滚互不影响内部回滚不影响外部外部回滚影响内部使用场景默认大多数场景日志记录、独立操作局部回滚场景代码示例ServicepublicclassOrderService{// 默认加入当前事务Transactional(propagationPropagation.REQUIRED)publicvoidcreateOrder(){// 如果调用方有事务就加入没有就新建}// 新建独立事务Transactional(propagationPropagation.REQUIRES_NEW)publicvoidlogOrder(){// 无论调用方有没有事务都新建一个// 外部事务回滚不影响这个日志记录}}八、事务失效场景高频考点Transactional不生效是线上最常见的问题之一。以下是最常见的失效场景8.1 自调用最经典问题代码ServicepublicclassUserService{TransactionalpublicvoidupdateUser(Useruser){// 事务方法}publicvoidupdateUserWithLog(Useruser){// ❌ 自调用——绕过了代理对象this.updateUser(user);// 事务不生效}}为什么失效this.updateUser()调用的是原始对象的方法而不是代理对象的方法。事务是通过代理对象实现的——只有通过代理对象调用方法事务才会生效。解决方案方案代码说明方案一注入自身Autowired private UserService self;通过代理对象调用推荐方案二AopContext((UserService) AopContext.currentProxy()).updateUser(user);需开启EnableAspectJAutoProxy(exposeProxy true)方案三拆分到不同类将事务方法移到另一个Service最干净推荐ServicepublicclassUserService{AutowiredprivateUserServiceself;// 注入自身代理对象TransactionalpublicvoidupdateUser(Useruser){...}publicvoidupdateUserWithLog(Useruser){self.updateUser(user);// ✅ 通过代理对象调用事务生效}}8.2 其他常见失效场景失效场景原因解决方案方法不是publicSpring AOP无法代理非public方法改为public方法被final修饰CGLIB无法重写final方法移除final修饰异常被try-catch吞掉事务拦截器收不到异常catch中重新抛出异常异常类型不匹配默认只回滚RuntimeException指定rollbackFor Exception.class类未被Spring管理没有Service等注解加上Service数据库引擎不支持事务MySQL使用MyISAM引擎改用InnoDB多线程调用子线程拿不到主线程的事务连接手动传递事务上下文传播行为配置不当配置了NOT_SUPPORTED或NEVER检查传播行为配置九、避坑要点错误/误区后果正确做法在同一个类中调用自己的事务方法事务不生效自调用注入自身代理对象或拆分到不同类在catch中吞掉异常事务不回滚重新抛出异常或手动rollback不指定rollbackFor检查异常不会触发回滚关键操作加rollbackFor Exception.class在Controller层加Transactional事务范围过大连接池压力大在Service层加事务事务方法中调用外部API事务时间过长锁持有太久事务中只做数据库操作忽略readOnly true性能浪费查询方法加readOnly true十、面试高频考点Q1Spring事务的底层原理是什么Spring事务基于AOP 动态代理实现。Spring在运行时为目标Bean创建代理对象通过TransactionInterceptor拦截目标方法的调用在方法执行前开启事务执行后根据结果提交或回滚事务。Transactional只是声明事务边界的元数据真正干活的是AOP代理。Q2Transactional默认回滚规则是什么默认只对未捕获的RuntimeException运行时异常和Error进行回滚而普通的Exception检查异常不会触发回滚。如果需要让检查异常也回滚需要指定rollbackFor Exception.class。Q3REQUIRED、REQUIRES_NEW、NESTED有什么区别REQUIRED是默认传播行为——有事务就加入没有就新建。REQUIRES_NEW无论如何都新建一个独立事务新老事务互不影响。NESTED在当前事务中创建嵌套事务——内部回滚不影响外部但外部回滚会让内部也回滚。Q4Transactional为什么会失效列举常见场景。常见失效场景包括①自调用同类中this调用绕过代理②方法非public③异常被catch吞掉④异常类型不匹配默认只回滚RuntimeException⑤方法被final修饰⑥类未被Spring管理⑦数据库引擎不支持事务。Q5Transactional放在Service层还是Controller层为什么放在Service层。事务应该包裹业务逻辑而不是请求处理。Controller层加事务会导致事务范围过大包含参数校验、数据转换等非数据库操作增加数据库连接持有时间影响性能。事务的最佳实践是事务中只做数据库操作不做外部API调用。 面试官追问陷阱加分题追问1“Transactional加了rollbackFor Exception.class但事务还是不回滚可能是什么原因” 除了检查异常的问题还有几种可能①自调用——事务方法被同类中的另一个方法直接调用this.xxx()绕过了代理②异常被catch后没有重新抛出③方法不是public④数据库引擎不支持事务如MySQL的MyISAM⑤多线程场景——子线程拿不到主线程的事务连接。追问2“REQUIRES_NEW和NESTED都能实现’内部回滚不影响外部’有什么区别”REQUIRES_NEW是独立事务——内部和外部是完全独立的两个事务各自有独立的连接和提交/回滚互不影响。NESTED是嵌套事务——内部事务是外部事务的子事务内部回滚不影响外部但外部回滚会导致内部也回滚。从资源消耗来看REQUIRES_NEW消耗更大新建独立连接NESTED更轻量使用保存点实现。十一、练习题简答题Spring事务默认的回滚规则是什么为什么检查异常默认不会触发回滚代码题在一个Service中方法A调用了方法B方法B有Transactional注解。请写出两种让方法B事务生效的解决方案。分析题某项目中Transactional注解在UserService.updateUser()方法上不生效但OrderService.createOrder()方法上的Transactional正常。updateUser()是被UserService内部的另一个方法调用的。请分析原因并给出解决方案。 你的学习进度当前第76篇 / 共108篇 ·进阶篇Spring全家桶第73~82篇✅ 已完成基础篇44篇 第45~76篇 正在学第76篇⏳ 待学习第77~108篇 完整目录 学习指南 | 订阅本专栏不错过每一篇 下一篇文章预告下一篇《第77篇Spring MVC流程》内容简介Spring MVC核心流程——DispatcherServlet、HandlerMapping、HandlerAdapter、ViewResolver从请求到响应的完整链路。Spring全家桶专题持续推进拿下Spring MVC《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇建议收藏 关注一起100天拿offer 点击关注我更新后第一时间收到推送
返回列表