spring源码分析之事务transaction上篇

spring源码分析之事务transaction上篇

大家基本上都用过事务,今天一起分析下spring源码中也比较重要的一个模块-事务。spring中事务这一块要完全使用好还是有一定难度,主要是很多细节需要注意,如果你还没有完全明白spring的事务,那么这篇文章肯定会让你收获满满。

一、创建代理

spring事务创建代理的流程和spring aop创建代理几乎是一模一样,不清楚的可以自行阅读相关资料或者参考这篇文章(spring aop分析)。这里稍微介绍创建代理之前spring会先创建几个重要的对象

我们从@EnableTransactionManagement这个事务的开关的入口开始

1.@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
   }

不多讲,直接看@Import里面的类,如果不明白的,可以阅读这篇文章(spring源码解析之ConfigurationClassPostProcessor分析

2.TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
   

   /** * Returns {@link ProxyTransactionManagementConfiguration} or * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY} * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, * respectively. */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
   
      switch (adviceMode) {
   
          //默认是PROXY,spring会讲该方法返回的string[]都实例化
         case PROXY:
            return new String[] {
   AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            return new String[] {
   determineTransactionAspectClass()};
         default:
            return null;
      }
   }
    //...省略
}

所以到这里,spring会实例化一个AutoProxyRegistrar对象和ProxyTransactionManagementConfiguration对象,其中AutoProxyRegistrar和AOP创建那个拦截是否需要代理的BeanpostProcessor一样,这里就不继续跟,感兴趣自行阅读。我们看ProxyTransactionManagementConfiguration。

3.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() {
   
      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;
   }

}

这里会创建三个对应的三个实例

BeanFactoryTransactionAttributeSourceAdvisor:是一个advisor,一般封装advice和pointcut

TransactionAttributeSource:用于解析事务标签属性

TransactionInterceptor:这个最重要,直接就是动态代理的调用的方法,其实现了MethodInterceptor接口。所以当调用生成的动态代理的方法时,会调用到TransactionInterceptor.invoke()方法,这也是我们今天分析的入口。其他的流程和springAOP流程一致,可自行阅读

二、创建事务源码分析

直接从TransactionInterceptor#invoke()开始分析

1.TransactionInterceptor.invoke()
public 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);
}

直接过,看invokeWithinTransaction

2.TransactionAspectSupport.invokeWithinTransaction()
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {

// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
//通过TransactionAttributeSource获取@Transactional注解中的属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
//这个if一般不会走到
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {

// Standard transaction demarcation with getTransaction and commit/rollback calls.
//1.这是创建事务的核心逻辑,非常重要
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.
//2.调用真是的业务逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {

// target invocation exception
//3.核心逻辑之一,事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {

cleanupTransactionInfo(txInfo);
}
if (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);
}
}
//4.核心逻辑之一,事务提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
//...省略代码,暂时先不看
}

事务-主要处理的逻辑如下

创建事务、调用业务逻辑、事务回滚、事务提交我们一个个来看,spring事务中隔离级别和mysql的隔离级别是一致的,但是spring中的传播属性是spring实现的,这就是难点之一,我们今天重点看的是如何正确处理好传播属性。分析之前,先描述下spring支持哪7重传播属性

REQUIRED:如有事务,则使用当前事务,没有则创建

SUPPORTS:如果有事务,就用当前事务;没有则不适用事务

MANDATORY:使用当前事务,如果当前事务没有则抛异常

REQUIRES_NEW:新建事务,如果当前存在事务,则将当前事务挂起

NOT_SUPPORTED:非事务方式执行,如果当前存在事务 ,就将当前事务挂起

NEVER:非事务方式执行,如果当前存在事务 ,就抛异常

NESTED:嵌套事务

其实最常用的就是REQUIRED(默认)、REQUIRES_NEW、NESTED,今天源码分析也只分析上面三种,也是最复杂的三种

本文以我下面的测试的代码为例子,进行分析

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public void testInsert() throws Exception {

String sql = "insert into user (name,age,sex) values(?,?,?)";
jdbcTemplate.update(sql,new Object[]{
"taott11",12,"man"});
//int a = 1/0;
//throw new Exception();
String sql2 = "insert into user (name,age,sex) values(?,?,?)";
jdbcTemplate.update(sql2,new Object[]{
"tao",18,"woman"});
//这里又调用了另外一个有事务标记的方法(动态代理方法)
productService.queryUesr();
}
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
public void queryUesr() throws Exception {

query();
throw new RuntimeException();
}

上述实例会调用两次动态代理的方法,一次是UserService.testInsert(),另外一次是ProductService.queryUesr(),请忽略类名和方法名,没任何含义,仅仅是测试使用而已

我们先从第一个代理方法开始进入分析,调用业务方法testInsert()之前先创建事务

3.createTransactionIfNecessary()
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {

txAttr = new DelegatingTransactionAttribute(txAttr) {

@Override
public String getName() {

//获取完成方法名
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {

if (tm != null) {

//1.核心逻辑
status = tm.getTransaction(txAttr);
}
else {

if (logger.isDebugEnabled()) {

logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

没什么重要的逻辑,我们重点看tm.getTransaction()

4.AbstractPlatformTransactionManager.getTransaction()
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {

// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
//1.创建一个事务对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//2.判断是否已经存在事务,第一次调用testInsert没有,第二次就有了,非常重要的方法
if (isExistingTransaction(transaction)) {

// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {

logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {

//3.开启事务
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);
}
}

重要的逻辑方法,我已经做了标注了,下面我们一个个看

4-1.doGetTransaction()

创建事务对象

protected Object doGetTransaction() {

DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//这个地方拿到数据库的连接,其实是从threadlocal中拿,第一次拿不到,因为没有设置进去,后面会详细将
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
//所以这个事务的连接其实是null
txObject.setConnectionHolder(conHolder, false);
return txObject;
}

第一次不会走到上面代码4中的注释2,因为不存在事务。所以我们直接看注释3,开启事务startTransaction

4-2.startTransaction()
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建了一个事务状态,请记住第三个参数为true,后面会用到
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开怎么开启事务的
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}

这里就是创建了一个DefaultTransactionStatus,这里第三个参数newTransaction=true希望大家先记住,这是spring事务的一个非常重要的细节,后面的提交和回滚都和参数有联系,只有该参数为true的条件下的事务才有资格提交和回滚,下面我们看doBegin

4-2-1.doBegin()
protected void doBegin(Object transaction, TransactionDefinition definition) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {

//1.给当前事务设置连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {

Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {

logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
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).
//2.必须要关闭自动提交设置手动提交,否则你提交代码就提交了事务
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.
//3.绑定连接
if (txObject.isNewConnectionHolder()) {

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {

if (txObject.isNewConnectionHolder()) {

DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}

这里重点的方法都标注出来了,我们一个个看

注释1:给当前事务设置连接,我们之前已经分析了,我们第一次调用testInsert()时,从threadlocal中是没取到ConnectionHolder(其实就是connection的封装),这里就从连接中获取一个connection然后封装成ConnectionHolder设置到事务对象中

注释2:这里就是要跟原生jdbc一样,使用事务,也要先将自动提交设置成手动提交

注释3:这里就比较重要了,其实就是将当前ConnectinoHolder设置到threadlocal中,方便第二个事务调用时能获取到,我们具体看下bindResource()里面的逻辑,还是非常有意思的

4-2-1-1.TransactionSynchronizationManager.bindResource()
public static void bindResource(Object key, Object value) throws IllegalStateException {

Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {

map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {

oldValue = null;
}
if (oldValue != null) {

throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {

logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
Thread.currentThread().getName() + "]");
}
}

这个方法就是往threadLocal中设置一个Map<Object,Object>,其中key是数据源,value是ConnectionHolder。这里为什么要用Map而不是直接存储ConnectionHolder呢?因为可能存在多数据源的情况,一个方法如果两个数据源不一样,而我们拿到的连接如果是一样的就有问题了。另外设置到threadlocal中,我们在同一个线程中就能获取到上一次存储的ConnectionHolder了。也就是当我们调用第二个事务方法productService.queryUer()方法时,就能获取到存储在ConnectionHolder了(单个数据源情况下)
//———————————————–强行分页—————————————————————//

到这里我们第一个方法userService.testInsert()的事务已经开启了,我们开始调用业务逻辑,而业务逻辑中又会调用ProductService.queryUser(),这又要进入上述的一样的逻辑了。相同的逻辑我就不继续讲了,我们直接将视野看到代码4中(AbstractPlatformTransactionManager.getTransaction),这里有几个地方需要注意

注释1:这里又创建了一个新的事务,但是事务的连接是从threadlocal中拿的,我们这里没有切换数据源,并且第一次调用UserService.testInsert开始事务时已经往threadlocal中设置了connectionHolder,所以我们这里创建的第二个事务是新的,但是连接和上一个连接是一样的

注释2:这里的if会判断为true,会调用一个非常重要的方法handleExistingTransaction(),下面会详细分析,代码不会走到注释3,因为if里面已经return了。开始看handleExistingTransaction

5.handleExistingTransaction()
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {

//1.传播属性为PROPAGATION_NEVER
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {

throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//2.传播属性为PROPAGATION_NOT_SUPPORTED
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {

if (debugEnabled) {

logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//3.传播属性为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;
}
}
//4.传播属性为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);
status.createAndHoldSavepoint();
return status;
}
else {

// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
//5.剩下的几种都走下面的逻辑
// 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");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//6.要特别注意第三个参数了为newTransaction=false
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

代码虽然很长,但是比较容易,无非就是根据上面的几种不同的传播属性,做不同的逻辑。本文重点分析常用的几种传播属性REQUIREDREQUIRES_NEWNESTED,其他的几种也很简单,大家自行分析。

先看REQUIRED,比较见到,看最下面一行就行了

5-1.REQUIRED
//要特别注意第三个参数了为newTransaction=false
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

创建了一个事务状态,但是它的newTransaction=false,也就是它没有资格真正的回滚和提交后面会详细讲

5-2.REQUIRES_NEW

直接看上面的注释3

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {

if (debugEnabled) {

logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//1.会把上一个事务给挂起
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {

//2.开始事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {

resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}

注释1:将上一个事务挂起,下面会分析

注释2:开始新的事务,这个地方和之前开启事务的逻辑一样,重新设置连接、将连接设置到threadlocal中、将自动提交设置成手动提交

下面我们看下注释1是如何挂起事务的

5-2-1.suspend
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {

if (TransactionSynchronizationManager.isSynchronizationActive()) {

List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {

Object suspendedResources = null;
if (transaction != null) {

//1.重点挂起的逻辑
suspendedResources = doSuspend(transaction);
}
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);
//2.返回一个对象,该对象封装了被挂起的事务信息,方便后面能重新拿得到
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
//...省
}

接着看注释1的逻辑doSuspend

5-2-1-1.doSuspend
protected Object doSuspend(Object transaction) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
//将当前事务对象connection设置成null
txObject.setConnectionHolder(null);
//解绑,其实就是从threadlocal中删除Map
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}

因为创建第二个事务的时候,会将第一个事务的connectionHolder设置进来,这里挂起的操作,就是将第一次设置到threadlocal中的connectionHolder删除掉,并且将当前事务的connection设置成null。然后上面代码5-2.REQUIRES_NEW中的注释2中开启事务startTransaction方法,会将新的connectionHolder设置到threadlocal中,注意,此时startTransaction生成的事务状态的newTransaction=true

5-3.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.
//1.创建事务状态
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
//2.创建回滚点
status.createAndHoldSavepoint();
return status;
}
else {

// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
return startTransaction(definition, transaction, debugEnabled, null);
}
}

注释1:创建事务状态,注意此的newTransaction=false

注释2:创建一个回滚点,支持部分回滚,其实就是简单的封装了jdbc,不清楚回滚点的可以自行查阅相关内容

不知不觉已经已经写了很多了,但是这仅仅只是介绍了创建事务的原理,还有事务回滚、事务提交、注意事项都没讲,原本以为一篇文章能全部讲完,但是写太长了怕大家阅读起来比较类有恐惧感,所以我将事务回滚、事务提交、注意事项写在下一篇文章,请移步到(spring源码分析之事务transaction下篇

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111198.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • VUE响应式原理-Dep类「建议收藏」

    VUE响应式原理-Dep类「建议收藏」classDep{constructor(){//存储订阅者this.subs=[]}//添加订阅者addSub(sub){if(sub&&sub.update){this.subs.push(sub)}}//通知订阅者notify(){//变量订阅者,执行更新this.subs.forEach(item=>item.update()).

  • 并行计算简介_并行计算实验报告

    并行计算简介_并行计算实验报告1什么是并行计算?串行计算: 传统的软件通常被设计成为串行计算模式,具有如下特点:一个问题被分解成为一系列离散的指令;这些指令被顺次执行;所有指令均在一个处理器上被执行;一个问题

  • generator的作用_对服从与执行的理解

    generator的作用_对服从与执行的理解理解 Generator 的执行

  • KeyValuePair和Dictionary详解:「建议收藏」

    KeyValuePair和Dictionary详解:「建议收藏」1、KeyValuePaira、KeyValuePair是一个结构体(struct);b、KeyValuePair只包含一个Key、Value的键值对。2、Dictionarya、Dictionary可以简单的看作是KeyValuePair的集合;b、Dictionary可以包含多个Key、Value的键值对。usingSystem;usingSystem.Collections.Generic;namespaceConsoleTest

  • jenkins allure_allure测试报告

    jenkins allure_allure测试报告前言jenkins集成了allure插件,安装插件后运行pytest+allure的脚本即可在jenkins上查看allure报告了。allure安装在运行代码的服务器本机,我这里是用的dock

  • 计算流体力学基础与网格概述(与书同行)——ANSYS ICEM CFD网格划分从入门到精通——丁源「建议收藏」

    计算流体力学基础与网格概述(与书同行)——ANSYS ICEM CFD网格划分从入门到精通——丁源「建议收藏」一、计算流体力学基础:1、 建立物理模型,将其抽象为数学、力学模型后,要分析几何体的空间影响区域;2、 建立整个几个形体与其空间影响区域(计算区域的CAD模型),将整个计算区域进行空间网格划分。3、 加入求解所需要的初始条件;4、 选择适当的算法,设置具体的控制求解过程和精度的一些条件,对所研究的问题进行分析,保存数据文件结果;5、 选择合适的后处理器(postprocessor)读取计算结果文件,分析并且显示出来。数值模拟方法:1、 有限差分法;2、 有限元法;3、 有限体积法;子域法

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号