一、事务基础概念
1. 事务四大特性 ACID
- 原子性 Atomic:一组操作要么全成功,要么全失败回滚,不可分割
- 一致性 Consistency:事务前后数据完整性约束不被破坏(主键、外键、唯一索引)
- 隔离性 Isolation:多个事务并发执行互不干扰,通过隔离级别控制脏读、不可重复读、幻读
- 持久性 Durability:事务提交后数据永久落库,宕机不丢失
2. 原生 JDBC 事务痛点
Connection conn = DriverManager.getConnection();
conn.setAutoCommit(false); // 关闭自动提交
try {
// DML操作
conn.commit();
} catch(Exception e) {
conn.rollback();
} finally {
conn.close();
}
问题:
- 重复模板代码,耦合业务
- 多数据源、多框架(MyBatis/JdbcTemplate)事务统一管理复杂
- 无法实现声明式事务,所有事务逻辑写死在代码
3. Spring 事务解决思路
统一抽象事务 API + AOP 声明式事务
- 抽象事务接口,屏蔽 JDBC/MyBatis/JPA 底层差异
- AOP 环绕通知自动拦截业务方法,自动开启、提交、回滚事务
- 两种使用方式:编程式事务、声明式事务(主流)
二、Spring 事务核心三大顶层接口
1. PlatformTransactionManager 事务管理器(核心)
统一事务操作规范,不同持久层提供不同实现,第三方数据源必须配置该 Bean
public interface PlatformTransactionManager {
// 获取事务状态(开启事务)
TransactionStatus getTransaction(TransactionDefinition definition);
// 提交事务
void commit(TransactionStatus status);
// 回滚事务
void rollback(TransactionStatus status);
}
常用实现类:
DataSourceTransactionManager:MyBatis、JdbcTemplate、Druid/Hikari 关系型数据库(最常用)JpaTransactionManager:JPA/HibernateRabbitTransactionManager:RabbitMQ 消息事务RedisTransactionManager:Redis 事务
2. TransactionDefinition 事务定义
封装事务所有配置属性:传播行为、隔离级别、超时时间、只读、回滚规则
3. TransactionStatus 事务状态
记录当前事务运行状态:是否新事务、是否已提交、是否回滚、是否有保存点
三、五大核心配置(@Transactional 注解全部对应)
1. 事务传播行为 propagation(重点,多方法嵌套事务)
控制方法嵌套调用时事务如何传递,7 种类型:
表格
| 传播类型 | 说明 |
|---|---|
| REQUIRED(默认) | 有事务就加入,无则新建事务 |
| REQUIRES_NEW | 无论有无外层事务,新建独立事务,外层回滚不影响内层 |
| SUPPORTS | 有事务就运行在事务,无事务则非事务运行 |
| NOT_SUPPORTED | 强制挂起当前事务,以非事务执行 |
| MANDATORY | 必须存在外层事务,否则抛异常 |
| NEVER | 禁止存在事务,有事务直接报错 |
| NESTED | 嵌套事务,基于保存点;外层回滚内层一起回滚,内层回滚不影响外层 |
2. 事务隔离级别 isolation(解决并发脏读 / 不可重复读 / 幻读)
底层依赖数据库支持,5 种级别:
DEFAULT:使用数据库默认隔离级别(MySQL InnoDB 默认 REPEATABLE READ)READ_UNCOMMITTED:读未提交,存在脏读、不可重复读、幻读READ_COMMITTED:读已提交,解决脏读,存在不可重复读、幻读(Oracle 默认)REPEATABLE_READ:可重复读,解决脏读、不可重复读,存在幻读(MySQL 默认)SERIALIZABLE:串行化,全部问题解决,性能最低,锁表
并发问题说明
- 脏读:事务 A 读到事务 B 未提交的数据,B 回滚导致 A 读到脏数据
- 不可重复读:同一事务内,两次查询同一数据,中间被其他事务修改提交,两次结果不一致
- 幻读:同一事务两次范围查询,中间其他事务插入新数据,第二次查询多出行
3. rollbackFor /noRollbackFor 回滚规则
Spring 默认:仅抛出 RuntimeException、Error 才自动回滚
rollbackFor = Exception.class:所有异常(包括受检 Exception)都回滚noRollbackFor = BusinessException.class:抛出该异常不回滚
4. timeout 事务超时时间
单位秒,事务执行超过时间自动回滚,默认 - 1 无限制
5. readOnly 只读事务
标记查询方法,数据库优化(不开启写锁),写操作会抛异常
四、两种事务使用方式
方式 1:编程式事务(极少使用)
手动编码控制事务,灵活性高,代码侵入强
方式 A:TransactionTemplate(推荐编程式)
@Service
public class OrderService {
@Autowired
private TransactionTemplate transactionTemplate;
public void createOrder() {
transactionTemplate.execute(status -> {
// 业务操作
orderMapper.insert();
stockMapper.deduct();
// 抛异常自动回滚
return null;
});
}
}
方式 B:原生 PlatformTransactionManager
手动开启、提交、回滚,代码冗余
方式 2:声明式事务(企业开发主流,AOP 实现)
1. 注解 @Transactional(最常用)
使用规则
- 加在 public 方法上(AOP 动态代理只能拦截 public)
- 推荐写在 Service 层业务方法 / 类上
- 底层:Spring AOP 环绕通知,方法执行前开启事务,正常结束提交,异常回滚
@Service
public class OrderServiceImpl implements OrderService {
// 完整配置示例
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
timeout = 30,
readOnly = false,
rollbackFor = Exception.class
)
@Override
public void placeOrder() {
// 扣库存、创建订单、记录流水
}
}
2. XML 声明式事务(老 SSM 项目)
<!-- 1.事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 2.事务通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="select*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 3.AOP切面拦截Service所有方法 -->
<aop:config>
<aop:pointcut expression="execution(* com.service.*.*(..))" id="servicePoint"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePoint"/>
</aop:config>
3. 开启注解事务支持
原生 Spring JavaConfig
@Configuration
@ComponentScan("com")
@EnableTransactionManagement // 开启事务注解驱动
public class SpringConfig {
// 必须注册事务管理器Bean
@Bean
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
SpringBoot
自动开启 @EnableTransactionManagement,只需注入数据源,自动装配 DataSourceTransactionManager,直接使用 @Transactional
五、Spring 事务底层 AOP 执行流程
- IOC 创建 Service 代理对象(JDK 动态代理 / CGLIB)
- 调用业务方法时,进入事务拦截器
TransactionInterceptor - 拦截器获取
@Transactional配置封装 TransactionDefinition - 调用
txManager.getTransaction()开启事务,关闭连接自动提交 - 执行目标业务方法
- 方法正常执行无异常:txManager.commit ()
- 方法抛出指定异常:txManager.rollback ()
- 释放数据库连接
六、高频事务失效场景(面试重点)
-
方法非 public @Transactional 写在 private/protected 方法,AOP 无法拦截,事务失效
-
同类内部方法自调用
@Service public class OrderService { public void a() { this.b(); // 直接this调用,不走代理,b的事务失效 } @Transactional public void b() {} }解决:通过容器代理对象调用
((OrderService)AopContext.currentProxy()).b() -
异常类型不匹配 抛出受检 Exception,未配置
rollbackFor = Exception.class,不回滚 -
异常被 try-catch 捕获未抛出
@Transactional public void test() { try { mapper.insert(); int i = 1/0; } catch (Exception e) { // 异常吞掉,AOP感知不到异常,不会回滚 } }解决:catch 后手动抛出新异常
-
多数据源未指定对应事务管理器 多库场景,未通过
@Transactional(transactionManager = "tx1")指定管理器 -
传播行为配置错误 如外层 REQUIRED、内层 NOT_SUPPORTED,内层操作无事务,异常不回滚
-
数据库引擎不支持事务 MySQL MyISAM 不支持事务,必须使用 InnoDB
七、多数据源事务简单配置
多个数据库需要配置多个 DataSourceTransactionManager,使用时指定管理器名称
@Bean("tx1")
public PlatformTransactionManager tx1(DataSource ds1) {
return new DataSourceTransactionManager(ds1);
}
@Bean("tx2")
public PlatformTransactionManager tx2(DataSource ds2) {
return new DataSourceTransactionManager(ds2);
}
使用:
@Transactional(transactionManager = "tx1", rollbackFor = Exception.class)
八、核心面试总结
- Spring 事务分为编程式、声明式,底层基于 AOP 动态代理
- 三大核心接口:
PlatformTransactionManager(管理器)、TransactionDefinition(配置)、TransactionStatus(状态) - @Transactional 核心属性:传播行为、隔离级别、回滚规则、只读、超时
- 默认只对 RuntimeException / Error 回滚,受检异常需手动指定 rollbackFor
- 事务失效九大场景是高频考点,核心根源:AOP 代理未生效、异常未抛出、数据库不支持事务
- SpringBoot 自动装配事务管理器,原生 Spring 必须手动注册 DataSourceTransactionManager + @EnableTransactionManagement