Spring事务隔离级别和传播性

2025年Java面试宝典抢先领:
🔗 网盘链接 提取码: 9b3g
一、事务隔离级别到底是什么?
面试官问Spring事务隔离级别时,其实在考察你对数据库并发问题的理解。Spring直接沿用了数据库的四种标准隔离级别:
-
READ_UNCOMMITTED(读未提交)
最宽松的级别,能读到别人未提交的数据。可能引发脏读——比如你读到同事正在修改但还没提交的订单金额,结果他回滚了,你拿的就是错误数据。 -
READ_COMMITTED(读已提交)
Spring默认隔离级别!只读取已提交的数据。解决了脏读,但可能有不可重复读问题——同一事务内两次查询结果不同(比如中间数据被其他事务修改了)。 -
REPEATABLE_READ(可重复读)
保证同一事务多次读取数据一致。但可能有幻读——你查订单表10条记录,这时别人新增一条订单,你再查变成11条了(MySQL的InnoDB通过间隙锁基本解决了幻读)。 -
SERIALIZABLE(串行化)
性能最低但最安全,所有操作串行执行,彻底解决并发问题。
👉 面试技巧:被问到“Spring事务默认隔离级别”时,一定要强调是READ_COMMITTED,并解释为什么(平衡性能与安全)。
二、传播性:事务嵌套的生存法则

事务传播性解决的是“方法A调用方法B时,B的事务如何加入A”的问题。核心七种传播行为:
| 传播行为 | 典型场景 | |-------------------|--------------------------------------------------------------------------| | REQUIRED(默认) | 如果当前有事务就加入,没有就新建。比如下单操作调用扣库存和写订单日志 | | REQUIRES_NEW | 挂起当前事务,新建独立事务。比如写操作日志必须成功,不受主事务回滚影响 | | NESTED | 嵌套事务,子事务回滚不影响主事务(Savepoint机制)。适用于可独立回滚的子操作 | | SUPPORTS | 有事务就加入,没有就非事务执行。适合查询方法 | | NOT_SUPPORTED | 非事务执行,挂起当前事务。比如需要强制读数据库最新数据的统计操作 | | MANDATORY | 必须在已有事务中运行,否则抛异常。用于强制事务上下文 | | NEVER | 必须在非事务环境执行,否则抛异常 |
高频面试题:
❓ “REQUIRES_NEW和NESTED有什么区别?”
✅ REQUIRES_NEW:完全独立事务,互不影响
✅ NESTED:嵌套事务,子事务回滚不影响主事务,但主事务回滚会导致子事务回滚(基于Savepoint实现)
三、面试官最爱挖的坑
-
坑1:@Transactional不生效
- 原因:自调用(方法A调本类方法B)、非public方法、异常被catch未抛出、数据库引擎不支持事务(如MyISAM)
-
坑2:错误使用传播行为
// 错误示例:在循环中频繁创建新事务 @Transactional(propagation = Propagation.REQUIRES_NEW) public void processItem(Item item) { ... }这样写会导致每个循环项都开新事务,性能急剧下降!
-
坑3:混淆隔离级别和传播性
- 隔离级别解决的是“多个事务同时操作数据时如何隔离”
- 传播性解决的是“事务方法相互调用时如何传递”
四、实战避坑指南

避坑口诀:
默认隔离READ_COMMITTED,
传播就用REQUIRED。
特殊场景显声明,
嵌套独立要分清!
返利小贴士:
🎉 需要开通面试鸭会员?通过 面试鸭返利网 找我下单,可额外返现25元!后台私信订单号即可~
延伸思考:
Spring的@Transactional注解本质是通过AOP代理实现的,所以同类自调用会失效。解决方案:
- 将内部方法抽到新类中
- 通过AopContext获取代理对象(需开启
@EnableAspectJAutoProxy(exposeProxy = true)) - 最简单粗暴的——直接用
this.serviceB.method()(但要注意循环依赖)
理解清楚Spring事务隔离级别和传播性,能让你在分布式事务、高并发场景的设计中游刃有余。面试时结合具体业务场景说明选型依据,绝对是加分项!


