Spring事务机制
核心思想
Spring事务管理的核心思想是:将复杂多变的事务管理能力抽象成一个统一的平台,让开发者可以专注于业务逻辑,而不必处理不同数据源(如JDBC, JPA, Hibernate)各自的事务API。
它实现了声明式事务(Declarative Transaction),即通过配置(XML或注解)来定义事务规则(传播行为、隔离级别等),而无需在业务代码中编写繁琐的事务控制代码(如beginTransaction()
, commit()
, rollback()
)。Spring在运行时自动将这些规则应用到方法上。
关键组件
要实现这个抽象,Spring主要依赖以下几个核心接口和组件:
PlatformTransactionManager
(平台事务管理器)- 这是Spring事务抽象的核心接口。所有的事务策略(无论是JDBC、JPA还是JTA)都通过这个接口的实现类来完成。
- 它定义了事务操作的基本方法:
getTransaction()
,commit()
,rollback()
。 - 常见实现类:
DataSourceTransactionManager
: 用于单一的JDBC数据源(使用java.sql.Connection
来实现事务)。JpaTransactionManager
: 用于JPA(底层通常还是Hibernate)。HibernateTransactionManager
: 用于原生Hibernate。JtaTransactionManager
: 用于分布式事务(JTA),可以管理多个数据源的事务。
事务定义 (
TransactionDefinition
)- 它定义了事务的属性,也就是我们常配置的那些东西:
- 传播行为 (Propagation Behavior): 例如,
REQUIRED
(如果当前没有事务,就新建一个;如果有,就加入)、REQUIRES_NEW
(新建一个事务,挂起当前事务)等。 - 隔离级别 (Isolation Level): 例如,
READ_COMMITTED
(读已提交)、REPEATABLE_READ
(可重复读)等。 - 超时时间 (Timeout)
- 是否只读 (Read-Only)
- 传播行为 (Propagation Behavior): 例如,
- 我们使用的
@Transactional
注解的属性,最终就会被解析成一个TransactionDefinition
对象。
- 它定义了事务的属性,也就是我们常配置的那些东西:
事务状态 (
TransactionStatus
)- 它代表了事务的当前状态,比如事务是否是新创建的、是否已完成、是否有回滚标记等。
PlatformTransactionManager
的getTransaction()
方法返回的就是一个TransactionStatus
对象。
- 它代表了事务的当前状态,比如事务是否是新创建的、是否已完成、是否有回滚标记等。
实现原理:AOP + 动态代理
Spring事务的声明式实现,其底层技术是 AOP(面向切面编程) 和 动态代理。
简单来说,Spring在运行时为目标对象(你的Service类)创建一个代理对象。当你调用一个被@Transactional
标记的方法时,实际上是在调用代理对象的方法。这个代理方法会在你的业务方法执行“之前”和“之后”,由Spring事务拦截器 (TransactionInterceptor
) 自动加入事务管理的代码。
这个过程可以分解为以下几个步骤:
解析和注册:
- 当Spring容器启动时,它会解析所有Bean的定义。
- 如果发现某个Bean的方法上有
@Transactional
注解(或者XML配置了事务通知),Spring会意识到这个Bean需要被事务管理。
创建代理:
- Spring使用AOP机制(默认是CGLIB动态代理,如果类实现了接口,也可以用JDK动态代理)为这个Bean创建一个代理对象(Proxy),并将
TransactionInterceptor
(事务拦截器)作为一个“通知(Advice)”织入到这个代理对象中。 - 最终,注入到其他Bean(如Controller)中的,实际上是这个代理对象,而不是原始的目标对象。
- Spring使用AOP机制(默认是CGLIB动态代理,如果类实现了接口,也可以用JDK动态代理)为这个Bean创建一个代理对象(Proxy),并将
方法调用流程(核心):
当你通过代理对象调用一个事务方法时(例如userService.createUser()
),调用链如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 伪代码,展示代理对象的执行逻辑
public class UserServiceProxy extends UserService {
private TransactionInterceptor txInterceptor;
public void createUser() {
// 1. 前置处理:开启事务
TransactionStatus status = txInterceptor.getTransactionManager().getTransaction(txInterceptor.getTransactionAttributes());
try {
// 2. 回调:执行目标对象的真实业务方法
super.createUser(); // 你的业务代码在这里执行
// 3. 后置处理:如果没有异常,提交事务
txInterceptor.getTransactionManager().commit(status);
} catch (Exception e) {
// 4. 异常处理:根据配置的异常类型决定回滚还是提交
if (txInterceptor.rollbackOn(e)) {
txInterceptor.getTransactionManager().rollback(status);
} else {
txInterceptor.getTransactionManager().commit(status);
}
throw e;
}
}
}TransactionInterceptor
是这个流程的核心协调者。它会:
a. 根据@Transactional
的配置,创建一个TransactionDefinition
。
b. 调用PlatformTransactionManager
,根据定义获取事务(getTransaction
),并返回一个TransactionStatus
。
c. 执行业务方法(invocation.proceedWithInvocation()
)。
d. 业务方法成功返回,调用commit()
。
e. 业务方法抛出异常,根据规则判断是否需要进行rollback()
。
工作流程总结
- 配置事务管理器:在Spring配置中定义一个
PlatformTransactionManager
Bean(如DataSourceTransactionManager
)。 - 启用事务管理:使用
@EnableTransactionManagement
(Java Config)或<tx:annotation-driven/>
(XML)来启用基于注解的事务管理。 - 标记事务方法:在Service层的类或方法上使用
@Transactional
注解。 - Spring容器启动:解析注解,为被标记的Bean创建代理对象,并织入事务拦截逻辑。
- 方法调用:
- Controller调用
userService.createUser()
,实际调用的是代理对象的方法。 - 代理对象委托给
TransactionInterceptor
。 - 拦截器开启事务 -> 调用原始业务方法 -> 根据成功或异常提交或回滚事务。
- Controller调用
重要提醒
- 自调用问题:在同一个类中,一个非事务方法A调用另一个事务方法B,事务会失效。因为A调用的是
this.B()
,而不是代理对象的proxy.B()
,所以事务拦截逻辑不会被执行。必须通过代理对象调用才行。 - 异常回滚:默认只在抛出运行时异常(
RuntimeException
及其子类)和 Error 时回滚。受检异常(Checked Exception) 不会导致回滚。可以通过@Transactional(rollbackFor = Exception.class)
来改变默认行为。 - 选择正确的管理器:确保你使用的
PlatformTransactionManager
与你的持久化技术(JDBC, JPA, Hibernate)匹配。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 技术之路!
评论