Spring事务管理有 声明式事务 和 编程式事务 两种方式,实现对数据库操作的ACID控制。其核心思想是将事务管理与业务逻辑解耦,开发者通过简单注解或配置即可管理复杂事务。
开启Spring事务,本质上就是在Spring容器中增加了一个Advisor,拦截带有@Transaction的方法,在初始化后阶段创建代理对象。当代理对象执行方法前,设置数据库连接的autocommit改为false,在方法正常返回时执行commit,在异常时执行rollback。
本文中源码来自Spring 5.3.x分支,github源码地址:github.com/spring-proj...
一 创建代理对象
当在配置类上使用@EnableTransactionManagement注解时,通过@Import导入了TransactionManagementConfigurationSelector类。
该注解有两个属性
- proxyTargetClass:使用基于类的Cglib代理技术,默认为false。即使用JDK动态代理;
- AdviceMode:代理模式,枚举值有PROXY、ASPECTJ,默认为基于通知的JDK代理。
Java
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
TransactionManagementConfigurationSelector是ImportSelector接口实现,在selectImports方法中,引入了两个bean:
- AutoProxyRegistrar:在初始化后阶段创建代理对象;
- ProxyTransactionManagementConfiguration:定义Pointcut、Advice,创建Advisor。
有了这两个bean,Spring就能自行判断哪些bean需要被代理,代理逻辑是什么,从而创建代理对象。
1.1 AutoProxyRegistrar类
AutoProxyRegistrar类是ImportBeanDefinitionRegistrar接口的实现,在registerBeanDefinitions方法中,向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的beanDefinition。
而InfrastructureAdvisorAutoProxyCreator 继承了AbstractAdvisorAutoProxyCreator,本质上是一个BeanPostProcessor。
其作用就是开启自动代理,在初始化后阶段去寻找容器中Advisor类型的Bean,判断并为某个Bean创建代理对象。
1.2 ProxyTransactionManagementConfiguration类
该类是一个配置类,它又定义了三个bean,创建了Advisor对象:
- AnnotationTransactionAttributeSource:相当于Pointcut,判断某个类或方法上是否存在@Transactional注解;
- TransactionInterceptor:一个Advice,定义了代理逻辑;
- BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor,由AnnotationTransactionAttributeSource、TransactionInterceptor组成。
二 执行事务的大体流程
2.1 相关接口
PlatformTransactionManager
:事务管理器的顶层接口,定义了事务的提交(commit
)、回滚(rollback
)和获取当前事务状态(getTransaction
)的方法。TransactionDefinition
:定义事务的属性(传播行为、隔离级别、超时时间、是否只读等)。TransactionStatus
:描述事务的运行时状态(是否完成、是否回滚等)。
PlatformTransactionManager
常见实现类有:
-
- JDBC:
DataSourceTransactionManager
(适用于原生JDBC或MyBatis) - JPA:
JpaTransactionManager
- Hibernate:
HibernateTransactionManager
- JTA:
JtaTransactionManager
(分布式事务)
- JDBC:
2.2 执行流程
当代理对象在执行某个方法时,会再次判断方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行
TransactionInterceptor.invoke()方法,基本流程为:
- 利用所配置的PlatformTransactionManager获取一个数据库连接(其中会处理事务传播行为);
- 修改数据库连接的autocommit为false;
- 执行MethodInvocation.proceed()方法,即执行业务方法;
- 如果方法没有抛异常,则提交事务;
- 如果方法抛了异常,则回滚事务。
Java
// 伪代码:TransactionInterceptor的核心逻辑
public Object invoke(MethodInvocation invocation) {
// 1. 获取事务属性(@Transactional配置)
TransactionAttribute txAttr = getTransactionAttribute(method);
// 2. 获取事务管理器(PlatformTransactionManager)
PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 3. 根据传播行为决定是否创建新事务
TransactionStatus status = tm.getTransaction(txAttr);
try {
// 4. 执行业务方法
Object result = invocation.proceed();
// 5. 提交事务
tm.commit(status);
return result;
} catch (Exception ex) {
// 6. 根据异常类型回滚事务
completeTransactionAfterThrowing(txAttr, status, ex);
throw ex;
}
}
三 声明式事务和编程式事务
3.1 声明式事务
即通过@Transactional让业务方法按指定的事务类型执行。
- 创建DataSource、DataSourceTransactionManager
Java
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource dataSource() {
// 配置数据源(如HikariCP)
return new HikariDataSource();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
- 使用@Transactional
Java
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
// 指定传播行为和隔离级别
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public void createOrder(Order order) {
orderDao.save(order);
// 其他数据库操作(如更新库存)
updateInventory(order.getItems());
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateInventory(List<Item> items) {
// 更新库存逻辑
}
}
3.2 编程式事务管理
- 使用TransactionTemplate
Java
@Service
public class PaymentService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private PaymentDao paymentDao;
public void processPayment(Payment payment) {
transactionTemplate.execute(status -> {
try {
// 执行数据库操作
paymentDao.save(payment);
return true;
} catch (Exception e) {
// 标记回滚
status.setRollbackOnly();
return false;
}
});
}
}
- 直接使用PlatformTransactionManager
Java
public void manualTransaction() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务操作
transactionManager.commit(status);
} catch (Exception ex) {
transactionManager.rollback(status);
throw ex;
}
}
下一篇文章中将详细介绍事务的传播机制。