Spring事务管理(数据一致性)
📅 2026/7/22 7:03:48
👁️ 阅读次数
📝 编程学习
1. 基础/核心
1.1、Spring 支持哪两种事务管理方式?(编程式事务、声明式事务)
- 编程式事务:使用
TransactionTemplate或PlatformTransactionManager手动编写代码控制事务的提交与回滚。灵活度高,但代码侵入性强。 - 声明式事务:基于AOP(面向切面编程),通过
@Transactional注解或 XML 配置将事务管理与业务代码分离。代码无侵入,最常用。
1.2、@Transactional注解有哪些常用的属性?
propagation:事务传播行为(默认REQUIRED)。isolation:事务隔离级别(默认DEFAULT)。timeout:事务超时时间(单位:秒)。readOnly:只读事务。优化只读操作的性能,限制事务内的写操作。rollbackFor:指定哪些异常触发回滚(Spring 默认仅在遇到RuntimeException和Error时回滚)。noRollbackFor:指定哪些异常不触发回滚。
2. 高频/进阶
2.1、【必考】Spring 事务的传播行为(Propagation)有哪些?
Spring 共定义了 7 种传播行为,用于解决业务方法互相调用时,事务如何流转的问题:
REQUIRED(默认):如果当前存在事务,则加入该事务;如果不存在,则创建一个新事务。外层与内层方法共用同一个事务,任何地方报错全盘回滚。REQUIRES_NEW:创建一个新事务。如果当前存在事务,则将当前事务挂起。内层新事务的提交或回滚独立于外层事务,互不影响。NESTED:如果当前存在事务,则在嵌套事务内执行(利用数据库的Savepoint 保存点)。内层事务回滚会跳回保存点,不影响外层事务提交;但外层事务回滚,内层嵌套事务会随之回滚。- 其他 4 种:
SUPPORTS(有则用,无则无)、NOT_SUPPORTED(以非事务运行,有则挂起)、MANDATORY(必须在事务中运行,否则报错)、NEVER(不能在事务中运行,否则报错)。
2.2、Spring 事务的隔离级别有哪些?它们和数据库的隔离级别有什么关系?
Spring 的Isolation枚举定义了 5 个隔离级别:
DEFAULT:使用底层数据库默认的隔离级别(MySQL 默认为RR,Oracle 默认为RC)。READ_UNCOMMITTED(读未提交):引发脏读、不可重复读、幻读。READ_COMMITTED(读已提交):解决脏读,引发不可重复读、幻读。REPEATABLE_READ(可重复读):解决脏读、不可重复读,引发幻读。SERIALIZABLE(串行化):解决所有并发问题,性能最低。- 关系:Spring 事务隔离级别是对底层数据库能力的封装。如果数据库(如底层未开启某隔离级别)不支持,Spring 配置的隔离级别将无法生效。
3. 源码/深度
3.1、【必考】Spring 事务在什么情况下会失效?
- 内部方法自调用:在同一个类中,A 方法(无事务)通过
this.B()调用本类带@Transactional的 B 方法,此时调用不走代理对象,事务失效。 - 修饰非
public方法:Spring 默认要求@Transactional只能应用在public方法上。修饰private、protected或package-private方法时,AOP 代理会直接忽略。 - 异常被内部
try-catch吞掉:业务代码自行捕获了异常却没有重新抛出,或者抛出了非RuntimeException(且未配置rollbackFor = Exception.class),导致 Spring 无法感知异常,事务正常提交。 - 数据库引擎本身不支持事务:如 MySQL 使用了
MyISAM存储引擎,而非InnoDB。 - 目标类未被 Spring 管理:类上漏掉了
@Service或@Component注解,该类不会生成 Spring Bean 及其代理对象。
3.2、Spring 事务的底层原理是什么?它是如何利用 AOP 和ThreadLocal实现的?
- AOP 拦截:Spring 在初始化 Bean 时,若发现方法上有
@Transactional,会通过 JDK 动态代理或 CGLIB 动生成代理对象。调用该方法时,会被TransactionInterceptor拦截。 - 连接绑定与 ThreadLocal:拦截器通过
PlatformTransactionManager获取数据库连接。为了确保在同一个事务周期内(例如 Service 调多个 DAO),所有数据库操作都使用同一个数据库连接,Spring 利用TransactionSynchronizationManager内部的ThreadLocal<Map<Object, Object>>将当前数据库连接(Connection)与当前线程进行绑定。 - 增强逻辑:代理对象在目标业务方法执行前开启事务(
autoCommit = false);执行业务方法(各个 DAO 从ThreadLocal拿同一个连接执行 SQL);若成功则提交(commit),若抛出指定异常则回滚(rollback),最后将连接从ThreadLocal中清除并关闭。
编程学习
技术分享
实战经验