Spring框架提供了强大的事务管理功能,其中注解方式是一种简便且常用的方式。通过使用注解,可以在方法或类级别上声明事务属性,从而实现对数据库操作的事务管理。以下是一个简单的案例,演示了如何使用Spring的注解方式进行事务管理。
假设有一个简单的银行应用,其中涉及两个业务方法:一个是从一个账户转账到另一个账户,另一个是查询账户余额。首先,我们需要在Spring配置文件中启用事务管理器。可以使用@EnableTransactionManagement
注解来启用注解驱动的事务管理。在配置类上添加该注解:
@Configuration
@EnableTransactionManagement
public class AppConfig {
// 配置数据源、实体管理器工厂等其他配置
}
接下来,定义一个简单的服务类,该类包含两个业务方法,并使用注解进行事务管理:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class BankService {
@Autowired
private AccountRepository accountRepository;
@Transactional
public void transferMoney(String fromAccount, String toAccount, double amount) {
Account from = accountRepository.findByAccountNumber(fromAccount);
Account to = accountRepository.findByAccountNumber(toAccount);
from.withdraw(amount);
to.deposit(amount);
accountRepository.save(from);
accountRepository.save(to);
}
@Transactional(readOnly = true)
public double getAccountBalance(String accountNumber) {
Account account = accountRepository.findByAccountNumber(accountNumber);
return account.getBalance();
}
}
在上述代码中,我们使用@Transactional
注解来声明事务边界。transferMoney方法涉及转账操作,因此我们希望该方法在一个事务内执行。getAccountBalance方法是一个只读操作,因此我们使用readOnly = true来优化事务。
最后,假设有一个简单的AccountRepository接口,用于访问数据库:
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, Long> {
Account findByAccountNumber(String accountNumber);
}
上面就是Spring事务使用的一个简单实例。其实Spring事务底层和AOP是十分类似的,它也会生成一个代理对象,甚至底层源码也有着异曲同工之妙(底层就是使用AOP),下面我们就来分析一下Spring事务的底层源码。
@EnableTransactionManagement
这个注解是用于开启Spring事务管理的。我们看一下这个注解干了什么。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
首先这个注解底层导入了一个TransactionManagementConfigurationSelector
类。我们进入这个类看看
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 默认是PROXY
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
// 表示不用动态代理技术,用ASPECTJ技术,比较麻烦了
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
由于我们默认的模式是PROXY
模式,所以会执行下面代码:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
其它的不用想太多,我们只需要知道,上面代码会往容器中增加两个类,分别是AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
。然后我们看AutoProxyRegistrar
:
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 注册InfrastructureAdvisorAutoProxyCreator,才可以Bean进行AOP
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
// 设置InfrastructureAdvisorAutoProxyCreator的proxyTargetClass为true
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}
ImportBeanDefinitionRegistrar
已经很熟悉了,它在容器启动源码和AOP源码都分析过,实现了这个接口,在容器初始化过程中会调用重写的registerBeanDefinitions
方法。然后这个方法里面的核心代码就是下面这句:
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
上面代码就是向容器中注入了一个InfrastructureAdvisorAutoProxyCreator
类。我们看一下这个类:
@SuppressWarnings("serial")
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
// 判断是不是一个合格的Advisor
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
我们可以发现它继承了AbstractAdvisorAutoProxyCreator
这个类,这个类在介绍AOP已经很熟悉了吧。这个类首先是一个BeanPostProcessor,它在bean初始化后会被调用它的父类AbstractAutoProxyCreator
的postProcessAfterInitialization
方法,获取容器中所有的Advisor。这是导入的第一个类,然后看看导入的第二个类ProxyTransactionManagementConfiguration
。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// AnnotationTransactionAttributeSource中定义了一个Pointcut
// 并且AnnotationTransactionAttributeSource可以用来解析@Transactional注解,并得到一个RuleBasedTransactionAttribute对象
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
首先这个类是一个配置类,它的核心逻辑就是向Spring容器中放入了三个bean,第一个BeanFactoryTransactionAttributeSourceAdvisor
,由名字也可以看出它是一个Advisor,我们知道Advisor是由切点(PointCut)和通知(Advice)来设置,我们看看它是怎么设置的。首先设置通知:
advisor.setAdvice(transactionInterceptor);
它的通知就是一个事务拦截器,我们在学习@Bean底层原理的时候,我们这里参数就是一个TransactionInterceptor
,所以它会去容器中找到这样的bean,那有没有这个bean呢,其实是有的,就是上面代码第三个注入的bean(这个Spring事务最核心的地方)。
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
知道了通知在哪里,下面就是设置切点。
advisor.setTransactionAttributeSource(transactionAttributeSource);
上面这个设置是和pointcut十分有关系的,它其实就是把注入的第二个bean设置进入了。
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// AnnotationTransactionAttributeSource中定义了一个Pointcut
// 并且AnnotationTransactionAttributeSource可以用来解析@Transactional注解,并得到一个RuleBasedTransactionAttribute对象
return new AnnotationTransactionAttributeSource();
}
TransactionAttributeSource
就是一个工具类,可以帮我们解析@Transactional
注解,并得到一个RuleBasedTransactionAttribute对象。
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
上面这句代码就是我们实际创建的Advisor类型,我们进去看看。
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
我们看它的获取切点直接会调用getPointcut
方法,然后返回一个this.pointcut
,我们看一下这个切点类型
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
这个切点的类型就是TransactionAttributeSourcePointcut
,它由一个匿名内部类重写了getTransactionAttributeSource
方法。我们进入这个类看看事务的Pointcut到底是怎么实现的。
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof TransactionAttributeSourcePointcut)) {
return false;
}
TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
}
@Override
public int hashCode() {
return TransactionAttributeSourcePointcut.class.hashCode();
}
@Override
public String toString() {
return getClass().getName() + ": " + getTransactionAttributeSource();
}
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}
首先设置类匹配:
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
//判断是否与上面的类匹配,如果是就返回false
return false;
}
//调用get方法,这个方法由前面的匿名内部类重写了
TransactionAttributeSource tas = getTransactionAttributeSource();
//判断当前类是否和我的pointcut匹配
return (tas == null || tas.isCandidateClass(clazz));
}
}
上面代码核心逻辑就是调用我们的匿名内部类重写的getTransactionAttributeSource
,返回一个具体的类的类型,然后调用tas.isCandidateClass
,判断返回的类型是否和我们的pointcut匹配,我们进入tas.isCandidateClass
方法。
//AnnotationTransactionAttributeSource这个实现类的
@Override
public boolean isCandidateClass(Class<?> targetClass) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
this.annotationParsers
这个就是解析器,然后调用解析器的parser.isCandidateClass
方法。
//SpringTransactionAnnotationParser这个解析器
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
上面就是使用注解工具,判断你当前类是否有Transactional
注解。上面就是类型匹配的逻辑,我们回到TransactionAttributeSourcePointcut
,下面看看方法是如何匹配的。
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
它同样是使用到了TransactionAttributeSource
工具类,调用tas.getTransactionAttribute
进行方法匹配。
//AbstractFallbackTransactionAttributeSource这个类
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 检查缓存里的结果,缓存里存了当前类和方法是否存在Transactional注解
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
// 解析,并缓存结果
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
dta.setDescriptor(methodIdentification);
dta.resolveAttributeStrings(this.embeddedValueResolver);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
上面代码除了判断你这个方法有没有加@Transactional
注解,还会解析方法的配置为一个TransactionAttribute
对象缓存起来,给后面真正解析去使用,解析细节后面再讲。
有了上面细节,一个类或其方法如果有@Transactional
注解,那么我们就可以为其生成代理对象了。下面假设我一个类或方法上面有@Transactional
注解,那么它底层到底是怎么运行的,下面我们着重分析。
先回顾一下Spring事务底层工作原理:
autoCommit
属性设置为falseSpring 事务传播机制是指在多个事务方法之间进行事务传播的规则和策略。在 Spring 中,当一个方法调用另一个方法时,可能会涉及到多个事务操作,而事务传播机制定义了这些事务之间的关系和行为。以下是 Spring 中的事务传播行为:
如果当前存在事务,则加入该事务,如果不存在事务,则创建一个新事务。这是默认的传播行为,大多数情况下都适用。如果当前存在事务,方法将在该事务中运行;否则,它将创建一个新事务。
如果当前存在事务,则加入该事务,如果不存在事务,则以非事务方式运行。适用于不需要事务管理的方法,但可以参与到已经存在的事务中。
如果当前存在事务,则加入该事务,如果不存在事务,则抛出异常。要求当前方法必须在一个已存在的事务中运行,否则抛出异常。
无论当前是否存在事务,都创建一个新事务,如果存在事务,则将其挂起。这个传播行为会为当前方法创建一个新的事务,与外部事务无关。
以非事务方式运行,如果存在事务,则将其挂起。
这个传播行为会为当前方法禁用事务,即使外部存在事务,也会将其挂起。
PROPAGATION_NEVER:
以非事务方式运行,如果存在事务,则抛出异常。要求当前方法必须在没有事务的环境下运行,否则抛出异常。
如果当前存在事务,则在嵌套事务内执行,如果不存在事务,则创建一个新事务。这个传播行为类似于 PROPAGATION_REQUIRED,但是允许存在嵌套事务,嵌套事务可以独立提交或回滚,但只有外部事务结束时,才能真正提交。
事务传播机制可以通过 @Transactional 注解来设置。
通过前面的介绍如果我们的类或方法上面加了@Transactional
注解,那么Spring就会利用AOP机制给当前类创建一个代理对象,单我们执行被代理对象的方法的时候,实际执行的是代理对象的invoke
方法。首先我们进入invoke
方法,这个方法在TransactionInterceptor
类中(和AOP中的MethodInterceptor对象类似)。
public Object invoke(MethodInvocation invocation) throws Throwable {
//获得被代理的目标类
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
// 执行后续的Interceptor,以及被代理的方法(执行真正的被代理类的方法)
return invocation.proceed(); // test() sql
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
方法核心是调用invokeWithinTransaction
方法。我们进入该方法:
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// TransactionAttribute就是@Transactional中的配置(拿到TransactionAttribute工具类)
TransactionAttributeSource tas = getTransactionAttributeSource();
// 获取@Transactional注解中的属性值
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 返回Spring容器中类型为TransactionManager的Bean(事务管理器)对象
final TransactionManager tm = determineTransactionManager(txAttr);
// ReactiveTransactionManager用得少,并且它只是执行方式是响应式的,原理流程和普通的是一样的
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
throw new IllegalStateException("Coroutines invocation not supported: " + method);
}
CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
Class<?> reactiveType =
(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
InvocationCallback callback = invocation;
if (corInv != null) {
callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
}
Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
if (corInv != null) {
Publisher<?> pr = (Publisher<?>) result;
return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) :
KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
}
return result;
}
// 把tm强制转换为PlatformTransactionManager,所以我们在定义时得定义事务管理器为PlatformTransactionManager类型
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// joinpoint的唯一标识,就是当前在执行的方法名字(拿到的方法的名字会被当作事务的名字)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// CallbackPreferringPlatformTransactionManager表示拥有回调功能的PlatformTransactionManager,也不常用
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 如果有必要就创建事务,这里就涉及到事务传播机制的实现了
// TransactionInfo表示一个逻辑事务,比如两个逻辑事务属于同一个物理事务
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.
// 执行下一个Interceptor或被代理对象中的方法
retVal = invocation.proceedWithInvocation(); // test() sql
}
catch (Throwable ex) {
// target invocation exception
// 抛异常了,则回滚事务,或者
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
上面代码中真正执行代理类的目标方法是retVal = invocation.proceedWithInvocation();
这个方法,然后前面的代码就是开启事务之前的准备,后面代码是事务结束之前的处理(是否提交还是回滚),下面这句代码就是真正的开始一个事务:
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
我们进入createTransactionIfNecessary
方法:
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
//txAttr就是我们前面获得的当前@Transactional注解的信息
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
//如果之前我们没有设置事务的名称,这里就会直接将此时调用的方法名设置为事务的名字
@Override
public String getName() {
return joinpointIdentification;
}
};
}
// 每个逻辑事务都会创建一个TransactionStatus,但是TransactionStatus中有一个属性代表当前逻辑事务底层的物理事务是不是新的
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//开启事务的核心代码
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 返回一个TransactionInfo对象,表示得到了一个事务,可能是新创建的一个事务,也可能是拿到的已有的事务
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
上面代码首先就是设置了当前事务的名字,然后调用status = tm.getTransaction(txAttr);
这句代码去真正的开启事务,我们进入该方法:
//AbstractPlatformTransactionManager类的
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
//这个对象就是我们前面获得的@Transactional注解信息的对象(作为参数传进来了)
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 得到一个新的DataSourceTransactionObject对象
// new DataSourceTransactionObject txObject
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// transaction.getConnectionHolder().isTransactionActive(),判断当前方法是否存在一个事务(这里就是处理事务传播机制了)
if (isExistingTransaction(transaction)) {
//如果存在一个事务就会调用handleExistingTransaction方法
return handleExistingTransaction(def, transaction, debugEnabled);
}
//当前的@Transactional注解有没有定义timeout,这里就是判断这个值是否设置合理
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 如果当前没有事务,就看我们的当前的传播机制是否为PROPAGATION_MANDATORY,这个机制下如果当前存在事务,则加入该事务,如果不存在事务,则抛出异常。所以这个方法抛出了异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 在当前Thread中没有事务的前提下,以下三个传播机制是等价的
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 没有事务需要挂起,不过TransactionSynchronization有可能需要挂起
// suspendedResources表示当前线程被挂起的资源持有对象(数据库连接、TransactionSynchronization)
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
// 开启事务后,transaction中就会有数据库连接了,并且isTransactionActive为true
// 并返回TransactionStatus对象,该对象保存了很多信息,包括被挂起的资源
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
上面代码核心是处理了事务的传播机制,首先调用isExistingTransaction(transaction)
判断当前是否存在事务,参数transaction
就是前面调用方法Object transaction = doGetTransaction();
获取到的,我们先看看这个对象是什么:
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
上面方法就是创建了一个DataSourceTransactionObject
,然后返回,这个对象对于每个加了@Transactional
的注解或者方法都会创建一个新的。TransactionSynchronizationManager.getResource(obtainDataSource());
就会从当前的事务管理器中获取到我们配置的DataSource对象。
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doGetResource(actualKey);
}
@Nullable
private static Object doGetResource(Object actualKey) {
// resources是一个ThreadLocal包装的Map,用来缓存资源的,比如缓存当前线程中由某个DataSource所创建的数据库连接
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
// 获取DataSource对象所对应的数据库连接对象
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
我们会从一个Map中拿到数据库的DataSource对象,这个map其实就是当前线程的ThreadLoacal对象。这个map的对象是在Spring AOP处理Advisor的时候创建的。
// key为DataSource对象,value为ConnectionHolder对象
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
然后回到doGetTransaction
方法,txObject.setConnectionHolder(conHolder, false);
这就代码就是将拿到的Connection连接设置到DataSourceTransactionObject
对象中。false表示当前连接不是新建的。然后回到isExistingTransaction(transaction)
方法,这个方法判断当前连接是否为空来判断是否有事务,这样就能确定当前是否有事务,然后作出不同的处理。
如果存在事务就执行handleExistingTransaction
。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
//如果之前存在事务,且当前事务的隔离级别为`TransactionDefinition.PROPAGATION_NEVER`,则抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//如果当前事务的隔离级别为PROPAGATION_NOT_SUPPORTED,这个隔离级别以非事务方式运行,如果存在事务,则将其挂起。这个传播行为会为当前方法禁用事务,即使外部存在事务,也会将其挂起。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 把当前事务挂起,其中就会把数据库连接对象从ThreadLocal中移除
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//如果隔离级别为PROPAGATION_REQUIRES_NEW,无论当前是否存在事务,都创建一个新事务,如果存在事务,则将其挂起
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//挂起
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
//如果之前事务的隔离级别为TransactionDefinition.PROPAGATION_NESTED,表示如果当前存在事务,则在嵌套事务内执行,如果不存在事务,则创建一个新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建一个savepoint
status.createAndHoldSavepoint();
return status;
}
else {
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
// 如果依然是Propagation.REQUIRED
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
上面方法核心就是根据不同的传播机制在之前有事务的情况下如何做出不同的处理,继续回到getTransaction
方法。
如果不存在事务就按照设置的传播机制的不同来分不同的情况处理,首先判断当前的事务传播机制是否为PROPAGATION_MANDATORY
,如果是就直接抛出一次,然后判断事务的隔离机制是否为PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED
,这三种隔离机制在当前没有事务的情况下是一样的,然后就执行挂起操作(这里思考为上面当前没有事务还需要挂起):
事务挂起的目的是,如果我们事务A中又有一个方法开启了一个新的事务B,由于事务A现在可能没执行完所以需要进行挂起,就是占处理方法调用保存当前的计数器一样的道理。
SuspendedResourcesHolder suspendedResources = suspend(null);
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// synchronizations是一个ThreadLocal>
// 我们可以在任何地方通过TransactionSynchronizationManager给当前线程添加TransactionSynchronization,
//我们可以先简单的把这句代码理解为当前是否开启过了事务,由于我们没有创建过事务,所以不会进入这个if
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 调用TransactionSynchronization的suspend方法,并清空和返回当前线程中所有的TransactionSynchronization对象
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// 挂起事务,把transaction中的Connection清空,并把resources中的key-value进行移除,并返回数据库连接Connection对象
suspendedResources = doSuspend(transaction);
}
// 获取并清空当前线程中关于TransactionSynchronizationManager的设置
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
// 将当前线程中的数据库连接对象、TransactionSynchronization对象、TransactionSynchronizationManager中的设置构造成一个对象
// 表示被挂起的资源持有对象,持有了当前线程中的事务对象、TransactionSynchronization对象
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
return null;
}
}
上面代码首先判断之前是否开启过了事务,如果是就会进入if,然后执行suspendedResources = doSuspend(transaction);
真正的挂起事务。
@Override
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
底层就是将之前事务的连接从ThreadLocal这个集合中remove掉,然后返回remove掉的连接对象,回到suspend
方法,suspendedResources
就接收到了remove掉的对象。然后继续执行suspend
方法,除了挂起之前事务的连接,下面代码还挂起了其它之前事务的其他信息:
// 获取并清空当前线程中关于TransactionSynchronizationManager的设置
//前面事务的名字
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
//readonly属性
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
//隔离级别
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
//是否活跃
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
上面代码就是挂起了有关之前事务的很多信息,和连接对象一样这些个对象都是ThreadLocal,做法也都是从ThreadLocal中删除,然后返回。最后就是返回了将前面信息封装好的对象。
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
上面代码我们一直用到了一个对象TransactionSynchronizationManager
,我介绍一下这个对象:
TransactionSynchronizationManager 是 Spring 框架中用于管理事务同步状态的工具类。它提供了一些静态方法,用于在事务管理过程中跟踪和管理与事务相关的资源状态。在 Spring 的事务管理中,可能涉及多个资源、多个参与者,TransactionSynchronizationManager 负责协调它们的状态。以下是 TransactionSynchronizationManager 的一些重要方法和功能:
- registerSynchronization:用于注册事务同步对象,这些对象将在事务提交或回滚时执行相应的操作。
这可以用于确保在事务提交或回滚时执行某些自定义逻辑,例如清理资源、发送消息等。
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 在事务提交后执行的逻辑
}
@Override
public void afterCompletion(int status) {
// 在事务完成后执行的逻辑
}
});
- bindResource / getResource / hasResource:用于在当前事务中绑定、获取和检查特定于事务的资源。
可以在事务中共享和管理一些资源,确保它们在整个事务中可用
// 在事务中绑定资源
TransactionSynchronizationManager.bindResource(key, resource);
// 获取事务中的资源
Object resource = TransactionSynchronizationManager.getResource(key);
// 检查是否存在事务中的资源
boolean hasResource = TransactionSynchronizationManager.hasResource(key);
- clearSynchronization / clear:用于清理事务同步状态,确保不再引用事务相关的资源。在事务完成后,通过清理可以释放资源,防止资源泄漏。
// 清理事务同步状态
TransactionSynchronizationManager.clearSynchronization();
// 清理特定资源
TransactionSynchronizationManager.clearResource(key);
- isSynchronizationActive:检查当前是否处于事务同步状态。这对于确定是否应执行某些事务同步逻辑非常有用。
boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
TransactionSynchronizationManager 通过使用线程本地变量(ThreadLocal)来存储事务同步状态,以确保在多线程环境中的正确性。它在 Spring 的事务管理中起到了协调各种资源、回调等操作的重要作用,帮助开发者更方便地与事务相关的逻辑。
如果当前没有事务,就会创建一个新的事务,核心的代码是startTransaction(def, transaction, debugEnabled, suspendedResources);
这句,这句就真正的开始了一个事务:
//Object transaction就是前面的DataSourceTransactionObject对象
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
// 是否开启一个新的TransactionSynchronization
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 开启的这个事务的状态信息:
// 事务的定义、用来保存数据库连接的对象、是否是新事务,是否是新的TransactionSynchronization
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务
doBegin(transaction, definition);
// 如果需要新开一个TransactionSynchronization,就把新创建的事务的一些状态信息设置到TransactionSynchronizationManager中
prepareSynchronization(status, definition);
return status;
}
然后这个方法中调用了doBegin来真正开启事务:
//DataSourceTransactionManager类中
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
//获取前面设置的DataSourceTransactionObject对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
//建立一个连接对象
Connection con = null;
try {
// 如果当前线程中所使用的DataSource还没有创建过数据库连接,就获取一个新的数据库连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//使用DateSource创建一个新的连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
//然后将新建立的连接设置到DataSourceTransactionObject对象中,然后标记设置为true
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 根据@Transactional注解中的设置,设置Connection的readOnly与隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
// 设置autocommit为false
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
// 设置数据库连接的过期时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 把新建的数据库连接设置到resources中,resources就是一个ThreadLocal
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
//判断DataSourceTransactionObject这个对象是否是新建的,如果是就将当前对象中保存的Connection连接设置到ThreadLocal集合中
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
我们知道现在我们进入的是当前没有事务的情况,所以此时DataSource自然为空,所以首先使用DataSource创建一个新的连接。
Connection newCon = obtainDataSource().getConnection();
然后从Transactional注解中获得相关信息来设置隔离级别、readOnly属性(为true表示当前数据库连接只能执行读操作)
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
然后设置autoCommit属性
为false
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
然后设置超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
总的来说上面方法核心就是创建了一个新的数据库连接,我们回到getTransaction
方法。上面的代码主要就有事讲了之前有事务和之前没事务Spring事务源码针对不同的传播机制是如何处理的。下面就开始分析Spring是如何执行被代理对象的方法的。继续回到invokeWithinTransaction
方法。前面执行的代码是TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
,这个txInfo
就是前面一个事务挂起的资源对象,它是通过一系列处理变为TransactionInfo
对象的,下面就开始执行真正的被代理对象的方法逻辑了。
retVal = invocation.proceedWithInvocation();
当我们事务执行过程中抛出了异常,此时就要进行回滚逻辑,回滚方法如下:
completeTransactionAfterThrowing(txInfo, ex);
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
// transactionAttribute的实现类为RuleBasedTransactionAttribute,父类为DefaultTransactionAttribute
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
首先执行txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)
,前一个条件是判断属性是否为空,后面的条件就是执行了一个rollbackOn(ex)
函数。
@Override
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
// 遍历所有的RollbackRuleAttribute,判断现在抛出的异常ex是否匹配RollbackRuleAttribute中指定的异常类型的子类或本身
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
return super.rollbackOn(ex);
}
// ex所匹配的RollbackRuleAttribute,可能是NoRollbackRuleAttribute,如果是匹配的NoRollbackRuleAttribute,那就表示现在这个异常ex不用回滚
return !(winner instanceof NoRollbackRuleAttribute);
}
上面函数就是拿到@Transactional
注解中配置的rollbackfor
和norollbackfor
属性,然后判断当前的异常是否属于这两个属性的子类,如果是就执行相应的动作。进入if判断语句:
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
上面就是调用了一个rollback方法进行回滚。
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
// 比如mysql中的savepoint
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
// 回滚到上一个savepoint位置
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
// 如果当前执行的方法是新开了一个事务,那么就直接回滚
doRollback(status);
}
else {
// Participating in larger transaction
// 如果当前执行的方法,是公用了一个已存在的事务,而当前执行的方法抛了异常,则要判断整个事务到底要不要回滚,看具体配置
if (status.hasTransaction()) {
// 如果一个事务中有两个方法,第二个方法抛异常了,那么第二个方法就相当于执行失败需要回滚,如果globalRollbackOnParticipationFailure为true,那么第一个方法在没有抛异常的情况下也要回滚
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// 直接将rollbackOnly设置到ConnectionHolder中去,表示整个事务的sql都要回滚(设置到了数据库连接上)
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
cleanupAfterCompletion(status);
}
}
doRollback(status);就是真正的回滚,底层就是拿到数据库连接直接回滚。
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
当前事务完成了,如果成功了就可以提交事务了。关键是下面代码
commitTransactionAfterReturning(txInfo);
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 可以通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();来设置
// 事务本来是可以要提交的,但是可以强制回滚(手动进行回滚)
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
//执行强制回滚操作
processRollback(defStatus, false);
return;
}
// 判断此事务在之前是否设置了需要回滚,跟globalRollbackOnParticipationFailure有关
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
// 提交
processCommit(defStatus);
}
正常提交,调用processCommit(defStatus);
方法:
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
//这个方法就是调用前面我们介绍到的同步器TransactionSynchronizationManager的方法
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
//
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
//如果当前事务是新的事务,就可以直接提交了,不是的话就不能提交,因为事务还没有完成
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
// 恢复被挂起的资源到当前线程中
cleanupAfterCompletion(status);
}
}
如果我们的事务是一个新的事务就可以直接调用doCommit(status);
方法,它的逻辑就是拿到数据库连接然后调用commit
方法即可。
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw translateException("JDBC commit", ex);
}
}
提交完成后还需要恢复被挂起的逻辑,核心代码是 cleanupAfterCompletion(status);
方法。
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
// 这里会去关闭数据库连接,如果当前的事务是新建立的,我们还需要关闭这个连接
// System.out.println("关闭了数据库连接");
doCleanupAfterCompletion(status.getTransaction());
}
// 恢复被挂起的资源到当前线程中
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// 恢复
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}