Spring 学习笔记之 @Transactinal实现原理
Spring 框架中的@Transactional
注解是用来简化数据库事务管理的重要工具。下面详细介绍它实现数据库事务的原理。
核心原理概述
@Transactional
主要借助 Spring 的 AOP(面向切面编程)机制来达成事务管理。当一个方法被@Transactional
注解修饰时,Spring 会在该方法执行前后添加事务相关的处理逻辑,以保证方法内的数据库操作在一个统一的事务环境中进行。
具体实现步骤
1. 配置事务管理器
在 Spring 应用里,你得先配置一个事务管理器,这个管理器会和具体的数据源关联起来。例如,使用DataSourceTransactionManager
管理基于 JDBC 的事务。以下是 Java 配置示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;@Configuration
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
2. 启用事务注解支持
在 Spring 配置类上添加@EnableTransactionManagement
注解,以此开启@Transactional
注解的功能。
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@EnableTransactionManagement
public class AppConfig {// 其他配置
}
@EnableTransactionManagement
注解的作用就是开启这种声明式事务管理功能。
注解属性
- mode:用于指定 AOP 代理模式,有
AdviceMode.PROXY
(默认值,使用 Spring AOP 代理)和AdviceMode.ASPECTJ
(使用 AspectJ 进行切面织入)两种可选值。 - proxyTargetClass:仅在
mode
为AdviceMode.PROXY
时有效,若为true
则使用 CGLIB 代理,为false
则使用 JDK 动态代理。 - order:指定事务增强器的执行顺序。
工作流程
-
导入配置类:
@EnableTransactionManagement
注解借助@Import
注解导入TransactionManagementConfigurationSelector
类。 -
配置类选择:
TransactionManagementConfigurationSelector
会依据 AOP 代理模式来选择配置类。若使用 JDK 动态代理,就导入ProxyTransactionManagementConfiguration
类;若使用 CGLIB 代理,则导入AspectJTransactionManagementConfiguration
类。 -
注册事务增强器:所选的配置类会注册
BeanFactoryTransactionAttributeSourceAdvisor
事务增强器。这个增强器会扫描带有@Transactional
注解的方法,为其创建代理对象。
3. AOP 代理创建
当 Spring 容器启动时,它会扫描所有带有@Transactional
注解的类和方法,然后借助 AOP 为这些类或方法创建代理对象。Spring 提供了两种代理方式:JDK 动态代理和 CGLIB 代理。
- JDK 动态代理:若目标对象实现了接口,Spring 默认会使用 JDK 动态代理。
- CGLIB 代理:若目标对象没有实现接口,Spring 会使用 CGLIB 代理。
4. 事务拦截器插入
在代理对象中,Spring 会插入一个事务拦截器(TransactionInterceptor
)。这个拦截器会在目标方法执行前后进行事务管理。
@SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {...@Override@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}}
执行拦截器invoke方法的时候,主要业务逻辑在invokeWithTransaction方法里。
5. 事务拦截器工作流程
- 方法调用:当调用被
@Transactional
注解修饰的方法时,实际上调用的是代理对象的方法。 - 事务开启:事务拦截器会根据
@Transactional
注解的配置,从事务管理器获取一个事务,并开启这个事务。 - 目标方法执行:在事务开启后,拦截器会调用目标对象的实际方法,执行数据库操作。
- 事务提交或回滚:
- 正常情况:若目标方法正常执行完毕,没有抛出异常,事务拦截器会提交事务。
- 异常情况:若目标方法抛出了异常,事务拦截器会根据
@Transactional
注解的rollbackFor
和noRollbackFor
属性来判断是否需要回滚事务。若需要回滚,就会执行回滚操作。
invokeWithTransaction源代码如下,讲述了事务的具体执行流程。
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}if (retVal != null && txAttr != null) {TransactionStatus status = txInfo.getTransactionStatus();if (status != null) {if (retVal instanceof Future<?> future && future.isDone()) {try {future.get();}catch (ExecutionException ex) {Throwable cause = ex.getCause();Assert.state(cause != null, "Cause must not be null");if (txAttr.rollbackOn(cause)) {status.setRollbackOnly();}}catch (InterruptedException ex) {Thread.currentThread().interrupt();}}else if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}}commitTransactionAfterReturning(txInfo);return retVal;}
retVal = invocation.proceedWithInvocation(); 执行原始业务逻辑。
completeTransactionAfterThrowing(txInfo, ex); 处理碰到异常事务回滚。
commitTransactionAfterReturning(txInfo); 正常流程执行完成,提交事务。
示例代码
以下是一个简单的示例,展示如何使用@Transactional
注解:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(User user) {userRepository.save(user);// 可能会抛出异常的代码if (user.getName() == null) {throw new RuntimeException("用户名不能为空");}}
}
在上述示例中,createUser
方法被@Transactional
注解修饰。若方法执行过程中抛出RuntimeException
,事务会回滚,user
不会被保存到数据库。
总结
@Transactional
注解通过 Spring 的 AOP 机制,在目标方法执行前后插入事务管理逻辑,从而实现了数据库事务的自动管理。它大大简化了事务处理的代码,提升了开发效率。