Spring 事务管理?

2025年 阅读约 15 分钟 面试指南 · Spring Boot

深入解析Spring事务管理:声明式事务 vs 编程式事务、7种传播行为详解、隔离级别、失效原因汇总、事务原理源码分析,附面试模拟问答。

一句话总结

Spring 事务基于 AOP + ThreadLocal 实现。核心接口:PlatformTransactionManager(事务管理器,不同数据源有不同实现)。声明式事务(@Transactional,最常用)vs 编程式事务(TransactionTemplate,灵活但侵入)。传播行为(7种):REQUIRED(默认,有则加入无则新建)、REQUIRES_NEW(总是新建,挂起当前)、NESTED(嵌套事务,savepoint)。隔离级别:DEFAULT(跟随数据库,MySQL 默认 REPEATABLE_READ)。

初级理解

声明式事务 vs 编程式事务

# 声明式事务(推荐) @Service public class UserService { @Transactional public void createUser(User user) { userDao.insert(user); logDao.insert(new Log("创建用户")); } } # 编程式事务 @Service public class UserService { @Autowired private TransactionTemplate transactionTemplate; public void createUser(User user) { transactionTemplate.execute(status -> { userDao.insert(user); logDao.insert(new Log("创建用户")); return null; }); } } # 编程式事务适用场景: # 1. 只有少量操作需要事务 # 2. 需要精细控制事务边界 # 3. 动态决定是否回滚

中级深入

7 种传播行为

传播行为说明场景
REQUIRED(默认)有事务则加入,无则新建最常用,增删改操作
REQUIRES_NEW总是新建事务,挂起当前日志记录(不受主事务影响)
NESTED嵌套事务,通过 savepoint 回滚部分回滚场景
SUPPORTS有事务则加入,无则非事务执行查询操作
NOT_SUPPORTED非事务执行,挂起当前事务不需要事务的操作
MANDATORY必须在事务中,否则抛异常强制事务场景
NEVER不能在事务中,否则抛异常禁止事务场景
# REQUIRED vs REQUIRES_NEW 示例 @Service public class OrderService { @Transactional // REQUIRED(默认) public void createOrder() { orderDao.insert(order); // 操作1 logService.writeLog(); // 操作2(REQUIRES_NEW) // 如果操作3抛异常 throw new RuntimeException(); // 操作3 } # 结果:操作1 回滚,操作2 提交(独立事务) } @Service public class LogService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void writeLog() { logDao.insert(log); } }

高级拓展

事务原理 — AOP + ThreadLocal

# Spring 事务执行流程 # 1. @Transactional 方法被 AOP 代理拦截 # 2. TransactionInterceptor 调用 invoke() # 3. 获取 TransactionManager # 4. 判断传播行为 # 5. 开启事务(获取连接、设置 autoCommit=false) # 6. 绑定连接到 ThreadLocal(TransactionSynchronizationManager) # 7. 执行目标方法 # 8. 成功 → commit;异常 → rollback # 9. 清理 ThreadLocal、归还连接 # 为什么同一个事务中多次 DAO 操作用的是同一个连接? # 因为连接绑定在 ThreadLocal 上 # 同一个线程获取的都是同一个连接

隔离级别

# Spring 事务隔离级别 @Transactional(isolation = Isolation.READ_COMMITTED) # 5 种隔离级别 # DEFAULT:跟随数据库默认(MySQL = REPEATABLE_READ) # READ_UNCOMMITTED:读未提交(脏读、不可重复读、幻读) # READ_COMMITTED:读已提交(不可重复读、幻读) # REPEATABLE_READ:可重复读(幻读,MySQL InnoDB 通过 MVCC 解决) # SERIALIZABLE:串行化(无并发问题,性能最差)

实战场景

场景:多数据源事务

# 多数据源需要 JTA 分布式事务 # 或使用 Seata 等分布式事务框架 # 单数据源多 DAO 没问题 @Transactional public void transfer(Long fromId, Long toId, BigDecimal amount) { accountDao.decrease(fromId, amount); // 扣钱 accountDao.increase(toId, amount); // 加钱 // 同一个 DataSource,同一个连接,同一个事务 } # 多数据源需要指定 TransactionManager @Transactional(transactionManager = "orderTransactionManager") public void createOrder() { } @Transactional(transactionManager = "userTransactionManager") public void createUser() { }

面试模拟

面试官:Spring 事务的传播行为有哪些?

你:7 种。最常用:REQUIRED(默认,有则加入无则新建)、REQUIRES_NEW(总是新建独立事务)、NESTED(嵌套事务,savepoint 回滚)。其他:SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER。

面试官:REQUIRED 和 REQUIRES_NEW 有什么区别?

你:REQUIRED 如果当前有事务就加入,回滚时一起回滚;REQUIRES_NEW 总是新建事务,挂起当前事务,内外事务互不影响。典型场景:日志记录用 REQUIRES_NEW,即使主业务回滚,日志也要保留。