1. 基本概念
事务(Transaction)是一组不可分割的操作单元,这些操作要么全部成功执行,要么全部失败回滚,不存在部分成功的情况。
事务具有ACID特性:
- 原子性(Atomicity):事务是不可分割的最小单元。
- 一致性(Consistency):事务执行前后,数据状态保持合法(如转账后总金额不变)。
- 隔离性(Isolation):多个事务并发执行时,彼此互不干扰。
- 持久性(Durability):事务提交后,数据变更永久保存。
2.核心接口
Spring通过抽象层封装了不同的事务管理方式(如JDBC、Hibernate、MyBatis等),核心接口包括:
接口 | 作用 |
---|---|
PlatformTransactionManager | 事务管理器接口,定义了事务的提交、回滚等操作。 |
TransactionDefinition | 定义事务属性(隔离级别、传播行为、超时时间等)。 |
TransactionStatus | 表示事务的当前状态(是否活跃、是否已提交等)。 |
常见实现类:
DataSourceTransactionManager
:用于JDBC或MyBatis的事务管理。HibernateTransactionManager
:用于Hibernate的事务管理。
3. 方式
声明式事务管理
通过注解或XML配置声明事务规则,无需手动编写事务控制代码,侵入性低,是实际开发的首选。
核心注解:@Transactional
可标注在类或方法上,用于声明该类/方法需要事务管理。
示例:
@Service
public class UserService {// 声明式事务:方法执行时自动开启事务@Transactionalpublic void transferMoney() {// 业务逻辑:扣减A的余额,增加B的余额updateUserA();updateUserB();// 若方法正常结束,自动提交事务;若抛出异常,自动回滚}
}
4. @Transactional
注解的核心属性
@Transactional
提供了丰富的属性来配置事务行为:
属性 | 作用 | 可选值示例 |
---|---|---|
propagation | 事务传播行为(解决嵌套事务问题) | REQUIRED (默认)、REQUIRES_NEW 等 |
isolation | 事务隔离级别(解决并发问题) | READ_COMMITTED (默认)、SERIALIZABLE 等 |
readOnly | 是否为只读事务(查询操作可优化性能) | true /false (默认false) |
timeout | 事务超时时间(秒),超时自动回滚 | 如30 (30秒) |
rollbackFor | 指定触发回滚的异常类型 | 如Exception.class |
noRollbackFor | 指定不触发回滚的异常类型 | 如BusinessException.class |
关键属性详解
-
事务传播行为(
propagation
)
定义了多个事务方法嵌套调用时,事务如何传播。常见场景:REQUIRED
(默认):如果当前有事务,则加入;否则新建事务。REQUIRES_NEW
:无论当前是否有事务,都新建一个事务(原事务暂停)。SUPPORTS
:如果当前有事务,则加入;否则以非事务方式执行。
示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void logOperation() {// 日志记录,独立事务,即使主事务回滚也会提交 }
-
事务隔离级别(
isolation
)
解决并发事务引发的问题(脏读、不可重复读、幻读):READ_UNCOMMITTED
:最低级别,允许读取未提交的数据(可能脏读)。READ_COMMITTED
(默认):只能读取已提交的数据(避免脏读)。REPEATABLE_READ
:保证多次读取同一数据结果一致(避免不可重复读)。SERIALIZABLE
:最高级别,完全串行化执行(避免所有并发问题,但性能低)。
5. 事务回滚规则
- 默认情况下,
@Transactional
仅对未检查异常(RuntimeException
及其子类) 触发回滚,对已检查异常(如IOException
) 不回滚。 - 可通过
rollbackFor = Exception.class
指定对所有异常回滚:@Transactional(rollbackFor = Exception.class) public void transferMoney() throws Exception {// 任何异常都会触发回滚 }
6.实现原理
Spring声明式事务基于AOP(面向切面编程) 实现:
- 当方法标注
@Transactional
时,Spring通过AOP动态生成代理对象。 - 代理对象在方法执行前开启事务,执行后根据是否异常决定提交或回滚。
- 事务管理逻辑与业务逻辑解耦,通过"环绕通知"织入。
7. 常见问题与注意事项
-
@Transactional
失效场景:- 方法被
private
、final
修饰(AOP无法生成代理)。 - 同类中非事务方法调用事务方法(未经过代理对象)。
- 异常被
try-catch
捕获但未重新抛出(Spring无法感知异常)。 - 数据库引擎不支持事务(如MySQL的MyISAM,需改用InnoDB)。
- 方法被
-
自调用问题:
同类中方法A调用方法B(标注@Transactional
),事务会失效,因为未通过代理对象调用。
解决:注入自身Bean或使用AopContext.currentProxy()
获取代理对象。 -
性能优化:
- 查询操作设置
readOnly = true
(数据库可优化)。 - 避免事务范围过大(如将非数据库操作移出事务)。
- 查询操作设置
总结
Spring事务管理简化了传统JDBC事务的复杂性,声明式事务(@Transactional
)因其低侵入性成为主流选择。实际开发中需注意事务的传播行为、隔离级别及失效场景,确保数据一致性的同时兼顾性能。