spring系列-注解驱动原理及源码-声明式事务使用及原理解析

65 阅读15分钟

目录

一、环境准备

1、JdbcTemplate使用实例

2、事务添加

二、声明式事务源码分析

1、@EnableTransactionManagement

2、ProxyTransactionManagementConfiguration

3、核心:TransactionAspectSupport的invokeWithinTransaction

4、createTransactionIfNecessary创建事务

(1)事务管理器开启事务:getTransaction

(2)事务传播行为处理:handleExistingTransaction

5、TransactionAspectSupport的completeTransactionAfterThrowing,利用事务管理器回滚

6、TransactionAspectSupport的commitTransactionAfterReturning 事务提交

三、TransactionSynchronization监听

四、总流程图



一、环境准备

1、JdbcTemplate使用实例

(1)pom文件添加依赖

<!--c3p0数据源-->
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
</dependency>
<!--jdbc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

(2)创建配置类

package com.xiang.spring.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
* 声明式事务:
*
* 环境搭建:
*  1.导入相关依赖
*      数据源、数据库驱动、SpringJDBC模块。
*  2.配置数据源和JdkcTemplate(spring提供的简化数据库操作的工具)操作数据库
*
*/
@ComponentScan("com.xiang.spring.tx")
@Configuration
public class TxConfig {

    // 数据源
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("123698745");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        return dataSource;
    }

    /**
     * JdbcTemplate操作数据库
     * spring对@Configuration配置文件有特殊处理,给容器中添加组件的方法,多次调用都是从容器中找组件,组件只会创建一次。
      */
    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }
}

(3)添加service类和dao类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void insetUser() {
        userDao.insert();
        System.out.println("插入完成");
    }
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insert() {
        String sql = "insert into t_user(username, age) values(?, ?)";
        String username = UUID.randomUUID().toString().substring(0, 5);
        jdbcTemplate.update(sql, username, 19);
    }
}

(4)测试类查看结果

import com.xiang.spring.tx.TxConfig;
import com.xiang.spring.tx.UserService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Tx {

    @Test
    public void test01() {
        // 创建ioc容器,容器创建时,默认会将单例的bean都创建出来
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insetUser();
    }
}

2、事务添加

(1)给方法上标注@Transactional,标明这个方法是一个事务方法

/**
* 告诉spring这个方法是一个事务方法
*/
@Transactional
public void insetUser() {
    userDao.insert();
    System.out.println("插入完成");
    int i = 10/0;
}

(2)@EnableTransactionManagement开启基于注解的事务管理功能

@EnableTransactionManagement
@ComponentScan("com.xiang.spring.tx")
@Configuration
public class TxConfig {

(3)配置事务管理器来管理事务PlatformTransactionManager

/**
* 在容器中注册事务管理器
*/
@Bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {
    DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource());
    return dataSourceTransactionManager;
}

(4)如果事务方法报错,就会回滚。

二、声明式事务源码分析

1、@EnableTransactionManagement

(1)@EnableTransactionManagement利用TransactionManagementConfigurationSelector给容器中导入组件。

    导入两个组件AutoProxyRegistrar、ProxyTransactionManagementConfiguration。

(2)AutoProxyRegistrar给容器中注册一个InfrastructureAdvisorAutoProxyCreator组件。

    ① InfrastructureAdvisorAutoProxyCreator的作用只是利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用。(与AOP类似)

(3)ProxyTransactionManagementConfiguration 做了什么?

    ① 给容器中注册事务增强器。

        ① 事务增强器要用事务注解的信息。用AnnotationTransactionAttributeSource解析事务注解。

        ② 事务拦截器。

            TransactionInterceptor保存了事务的属性信息以及 事务管理器。

            TransactionInterceptor是一个MethodInterceptor方法拦截器。

            TransactionInterceptor在目标方法执行的时候,执行拦截器链,只有一个事务拦截器。

            ① 先获取事务的属性。

            ② 再获取PlatformTransactionManager(平台事务管理器),如果事先没有添加指定任何TransactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager。

            ③ 执行目标方法,如果异常,获取到事务管理器,利用事务管理器回滚这次操作。

            ④ 如果正常,利用事务管理器提交事务。

(1)TransactionManagementConfigurationSelector的selectImports方法

@Override
protected String[] selectImports(AdviceMode adviceMode) {
   switch (adviceMode) {
      case PROXY: // 默认就是PROXY
         return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
      case ASPECTJ:
         return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
      default:
         return null;
   }
}

2、ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor
  2. AnnotationTransactionAttributeSource:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut
  3. TransactionInterceptor:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Advice

AnnotationTransactionAttributeSource就是用来判断某个类上是否存在@Transactional注解,或者判断某个方法上是否存在@Transactional注解的。

TransactionInterceptor就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的invoke()方法。

package org.springframework.transaction.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

   @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
      BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
      advisor.setTransactionAttributeSource(transactionAttributeSource());
      advisor.setAdvice(transactionInterceptor());
      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() {
      TransactionInterceptor interceptor = new TransactionInterceptor();
      interceptor.setTransactionAttributeSource(transactionAttributeSource());
      if (this.txManager != null) {
         interceptor.setTransactionManager(this.txManager);
      }
      return interceptor;
   }
}

3、核心:TransactionAspectSupport的invokeWithinTransaction

调用目标方法时,会执行TransactionInterceptor 的invoke方法,最终调到invokeWithinTransaction方法。

  1. 利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接
  2. 修改数据库连接的autocommit为false
  3. 执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql
  4. 如果没有抛异常,则提交
  5. 如果抛了异常,则回滚
// org.springframework.transaction.interceptor.TransactionAspectSupport#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.
	// 获取@Transactional注解中的属性信息
	TransactionAttributeSource tas = getTransactionAttributeSource();
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 事务管理器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;
	}

	// 转换成PlatformTransactionManager,所以我们要定义为PlatformTransactionManager
	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
	// joinpoint的唯一标识,就是当前在执行的方法的名字
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	// CallbackPreferringPlatformTransactionManager表示拥有回调功能的PlatformTransactionManager,也不常用
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		// 如果有必要就创建事务,这里就涉及事务传播机制了
		// 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();
		}
		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;
	}

	else {
		Object result;
		final ThrowableHolder throwableHolder = new ThrowableHolder();

		// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
		try {
			result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
				TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
				try {
					Object retVal = invocation.proceedWithInvocation();
					if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
						// Set rollback-only in case of Vavr failure matching our rollback rules...
						retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
					}
					return retVal;
				}
				catch (Throwable ex) {
					if (txAttr.rollbackOn(ex)) {
						// A RuntimeException: will lead to a rollback.
						if (ex instanceof RuntimeException) {
							throw (RuntimeException) ex;
						}
						else {
							throw new ThrowableHolderException(ex);
						}
					}
					else {
						// A normal return value: will lead to a commit.
						throwableHolder.throwable = ex;
						return null;
					}
				}
				finally {
					cleanupTransactionInfo(txInfo);
				}
			});
		}
		catch (ThrowableHolderException ex) {
			throw ex.getCause();
		}
		catch (TransactionSystemException ex2) {
			if (throwableHolder.throwable != null) {
				logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
				ex2.initApplicationException(throwableHolder.throwable);
			}
			throw ex2;
		}
		catch (Throwable ex2) {
			if (throwableHolder.throwable != null) {
				logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
			}
			throw ex2;
		}

		// Check result state: It might indicate a Throwable to rethrow.
		if (throwableHolder.throwable != null) {
			throw throwableHolder.throwable;
		}
		return result;
	}
}

4、createTransactionIfNecessary创建事务

// org.springframework.transaction.interceptor.TransactionAspectSupport#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,但是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");
			}
		}
	}
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

(1)事务管理器开启事务:getTransaction

此处就使用事务管理器开启事务了。

// org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
		throws TransactionException {

	// Use defaults if no transaction definition given.
	TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

	// 得到一个新的DataSourceTransactionObject对象
	Object transaction = doGetTransaction();
	boolean debugEnabled = logger.isDebugEnabled();

	// transaction.getConnectionHolder().isTransactionActive()
	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'");
	}
	// 当前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);
	}
}

// org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction
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;
}




// org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		// 如果当前线程中所使用的DataSource还没有创建过数据库连接,就获取一个新的数据库连接
		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();

		// 根据@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.
        // 数据库连接绑定到线程
		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);
	}
}

最终,将Connection存放到ThreadLocal中。同一个线程保证使用同一个Connection。

(2)事务传播行为处理:handleExistingTransaction

开启事务之前,如果当前已经有事务了,就需要进行事务传播行为的判断。

先来看几种场景中的一种情况,a()在一个事务中执行,调用b()方法时需要新开一个事务执行:

  1. 首先,代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a

  2. 将数据库连接a的autocommit改为false

  3. 把数据库连接a设置到ThreadLocal中

  4. 执行a()方法中的sql

  5. 执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)

    1. 代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起
    2. 挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象
    3. 挂起完成后,再次利用事务管理器新建一个数据库连接b
    4. 将数据库连接b的autocommit改为false
    5. 把数据库连接b设置到ThreadLocal中
    6. 执行b()方法中的sql
    7. b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交
    8. 提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中
  6. a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交

这个过程中最为核心的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

// org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
private TransactionStatus handleExistingTransaction(
		TransactionDefinition definition, Object transaction, boolean debugEnabled)
		throws TransactionException {

	// 不支持事务
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
		throw new IllegalTransactionStateException(
				"Existing transaction found for transaction marked with propagation 'never'");
	}

	// 不支持新事务,所以后续的sql都不开事务了
	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);
	}

	// 新开事务
	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;
		}
	}

    // 创建一个savepoint
	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);
		}
	}

	// 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);
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

5、TransactionAspectSupport的completeTransactionAfterThrowing,利用事务管理器回滚

回滚需要判断指定的异常是否匹配。

注意这里有个savepoint的操作,一个事务可以指定savepoint,一段一段的回滚。

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
   if (txInfo != null && txInfo.hasTransaction()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
               "] after exception: " + ex);
      }
      if (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 ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw ex2;
         }
         catch (Error err) {
            logger.error("Application exception overridden by rollback error", ex);
            throw err;
         }
      }
      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 ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            throw ex2;
         }
         catch (Error err) {
            logger.error("Application exception overridden by commit error", ex);
            throw err;
         }
      }
   }
}

6、TransactionAspectSupport的commitTransactionAfterReturning 事务提交

protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
   if (txInfo != null && txInfo.hasTransaction()) {
      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;
        // 可以手动设置,强制回滚
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

		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);
	}

提交会调用提交的回调(自定义的监听),调用Connection的commit方法。

(注意,如果这个事务是本方法新建的,才能提交,这里涉及事务传播行为)

提交之后,需要恢复被挂起的资源。

最后需要关闭连接资源。

三、TransactionSynchronization监听

Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态。

@Component
public class UserService {

 @Autowired
 private JdbcTemplate jdbcTemplate;

 @Autowired
 private UserService userService;

 @Transactional
 public void test(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
    System.out.println("test被挂起了");
   }

   @Override
   public void resume() {
    System.out.println("test被恢复了");
   }

   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("test准备要提交了");
   }

   @Override
   public void beforeCompletion() {
    System.out.println("test准备要提交或回滚了");
   }

   @Override
   public void afterCommit() {
    System.out.println("test提交成功了");
   }

   @Override
   public void afterCompletion(int status) {
    System.out.println("test提交或回滚成功了");
   }
  });

  jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
  System.out.println("test");
  userService.a();
 }

 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void a(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

   @Override
   public void suspend() {
    System.out.println("a被挂起了");
   }

   @Override
   public void resume() {
    System.out.println("a被恢复了");
   }

   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("a准备要提交了");
   }

   @Override
   public void beforeCompletion() {
    System.out.println("a准备要提交或回滚了");
   }

   @Override
   public void afterCommit() {
    System.out.println("a提交成功了");
   }

   @Override
   public void afterCompletion(int status) {
    System.out.println("a提交或回滚成功了");
   }
  });

  jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
  System.out.println("a");
 }


}

四、总流程图

​编辑