Java异常分类与Spring事务回滚机制深度剖析
Java异常分类与Spring事务回滚机制深度剖析
作者:AI助手
日期:2025-05-22
一、前言
在企业级开发中,Spring的声明式事务(@Transactional
)极大简化了数据一致性的管理。但很多开发者对事务回滚与异常的关系、事务传播机制及其背后源码实现理解不够深入,容易踩坑。本文将系统梳理相关理论与实践,深入源码,助你彻底掌握Spring事务。
二、Java异常分类
2.1 异常体系结构
Java异常体系如下图:
Throwable
├── Error(严重错误,JVM级,程序无法处理)
└── Exception├── Checked Exception(受检异常,如IOException、SQLException)└── RuntimeException(运行时异常,如NullPointerException、IllegalArgumentException)
2.2 受检与非受检异常
- Checked Exception(受检异常)
必须显式声明throws
或捕获处理。比如IOException
、SQLException
。 - Unchecked Exception(运行时异常)
编译器不强制处理。比如NullPointerException
、IllegalArgumentException
。
口诀:
受检异常要声明,运行时异常可不管。
三、Spring事务原理
3.1 声明式事务的实现方式
Spring主要通过AOP代理实现声明式事务:
- 容器在Bean初始化时,自动为带有
@Transactional
的方法生成代理对象(JDK动态代理或CGLIB)。 - 代理对象拦截方法调用,事务拦截器(
TransactionInterceptor
)负责事务管理。
流程简图
业务方法调用↓
代理对象(AOP)↓
TransactionInterceptor(事务拦截器)↓
PlatformTransactionManager(策略接口,不同实现)↓
数据库事务
3.2 事务拦截器核心源码
// TransactionInterceptor#invoke
public Object invoke(final MethodInvocation invocation) throws Throwable {TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);PlatformTransactionManager tm = determineTransactionManager(txAttr);TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal;try {retVal = invocation.proceedWithInvocation(); // 执行业务代码} catch (Throwable ex) {completeTransactionAfterThrowing(txInfo, ex); // 异常处理throw ex;} finally {cleanupTransactionInfo(txInfo); // 清理}commitTransactionAfterReturning(txInfo); // 正常提交return retVal;
}
四、Spring事务回滚机制与异常关系
4.1 默认回滚规则
- 只对
RuntimeException
和Error
自动回滚 - 对
Checked Exception
(受检异常)不会自动回滚,除非配置rollbackFor
源码分析
// DefaultTransactionAttribute#rollbackOn
public boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);
}
4.2 自定义回滚规则
可通过@Transactional
注解参数配置:
rollbackFor
:指定哪些异常需要回滚noRollbackFor
:指定哪些异常不回滚
示例:
@Transactional(rollbackFor = IOException.class, noRollbackFor = NullPointerException.class)
public void foo() throws IOException { ... }
源码分析
// RuleBasedTransactionAttribute#rollbackOn
public boolean rollbackOn(Throwable ex) {// 遍历rollbackRules,匹配异常类型// ...省略if (winner == null) {return super.rollbackOn(ex);}return !(winner instanceof NoRollbackRuleAttribute);
}
4.3 捕获异常对事务的影响
如果业务代码catch住异常且未继续抛出,Spring事务感知不到异常,不会回滚。
示例:
@Transactional
public void bar() {try {// 业务代码} catch (Exception e) {// 异常被吞,事务不会回滚}
}
手动回滚方法:
@Transactional
public void baz() {try {// 业务代码} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}
五、Spring事务传播机制(Propagation)
5.1 传播行为类型
Spring定义了7种事务传播行为,主要包括:
REQUIRED
(默认):如果当前存在事务,则加入,否则新建事务REQUIRES_NEW
:总是新建事务,挂起原有事务NESTED
:嵌套事务,依赖底层数据库支持SUPPORTS
、MANDATORY
、NOT_SUPPORTED
、NEVER
5.2 传播机制源码分析
// AbstractPlatformTransactionManager#getTransaction
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {Object transaction = doGetTransaction();if (isExistingTransaction(transaction)) {// 已有事务,处理不同传播行为return handleExistingTransaction(definition, transaction, debugEnabled);}// 无事务,处理不同传播行为// ...
}
六、设计模式在Spring事务中的应用
- 代理模式:AOP代理实现方法拦截
- 策略模式:
PlatformTransactionManager
接口多策略实现(JDBC、JPA等) - 模板方法模式:
AbstractPlatformTransactionManager
定义事务模板,子类实现细节 - 责任链模式:AOP拦截器链
- 适配器模式:不同数据源通过实现同一接口适配Spring事务
七、常见误区与最佳实践
7.1 常见误区
-
误认为所有异常都会回滚
只有运行时异常和Error才自动回滚。 -
捕获异常未手动回滚
异常被catch并吞掉,需手动调用setRollbackOnly()
。 -
内部方法调用失效
同类内部调用@Transactional
方法不会被AOP代理增强,事务无效。
7.2 最佳实践
- 业务异常建议继承
RuntimeException
- 不要随意捕获异常,交给Spring处理回滚
- 需要受检异常回滚时,明确指定
rollbackFor
- 避免同类内部调用@Transactional方法
八、案例演示
@Service
public class DemoService {// 运行时异常,事务会回滚@Transactionalpublic void runtimeEx() {throw new RuntimeException("运行时异常,事务回滚");}// 受检异常,事务不会回滚@Transactionalpublic void checkedEx() throws IOException {throw new IOException("受检异常,事务不会回滚");}// 指定受检异常回滚@Transactional(rollbackFor = IOException.class)public void checkedExRollback() throws IOException {throw new IOException("受检异常,事务回滚");}// 捕获异常,不回滚@Transactionalpublic void catchEx() {try {throw new RuntimeException("异常被捕获,事务不会回滚");} catch (Exception e) {// 异常被吞}}// 手动强制回滚@Transactionalpublic void manualRollback() {try {throw new RuntimeException("异常被捕获,事务不会回滚");} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}}
}
九、总结与速记口诀
- 异常类型记: 运行时异常默认回滚,受检异常需声明。
- 回滚原理记: 事务拦截异常,运行时异常和错误才回滚。
- 自定义规则记: 指定回滚例外,规则优先匹配。
- 异常捕获记: 异常被吞事务不回滚,强制回滚需手动指定。
- 内部调用记: 内部调用无事务,代理之外才生效。
- 传播行为记: 传播行为定范围,异常影响全局。
十、参考资料与源码链接
- Spring官方事务文档
- TransactionInterceptor 源码
- AbstractPlatformTransactionManager 源码
- Spring事务传播机制详解
欢迎收藏、点赞、转发!如有问题欢迎评论区探讨。