Spring源码分析 6:事务

事务

Spring事务

  • Spring 中事务是用 AOP 切面技术来实现的。
  • 首先用注解的方式引入事务管理功能,代码如下

在这里插入图片描述

  • 引用这个注解就添加了注解事务功能,但是我们自己还是需要定义数据源和事务管理平台
  • 数据源和事务管理平台的加载都是在类 ProxyTransactionManagementConfiguration 进行的
  • 事务对应连接(connection),连接对应用户会话(session)

定义数据源

在这里插入图片描述

package org.example.dataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Component
public class DataSourceConfiguration {

    @Resource
    Environment environment;

    @Bean
    public DataSource comboPooledDataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass(environment.getProperty("jdbc.driverClassName"));
            comboPooledDataSource.setJdbcUrl(environment.getProperty("jdbc.url"));
            comboPooledDataSource.setUser(environment.getProperty("jdbc.username"));
            comboPooledDataSource.setPassword(environment.getProperty("jdbc.password"));
            comboPooledDataSource.setMinPoolSize(10);
            comboPooledDataSource.setMaxPoolSize(100);
            comboPooledDataSource.setMaxIdleTime(1800);
            comboPooledDataSource.setAcquireIncrement(3);
            comboPooledDataSource.setMaxStatements(1000);
            comboPooledDataSource.setInitialPoolSize(10);
            comboPooledDataSource.setIdleConnectionTestPeriod(60);
            comboPooledDataSource.setAcquireRetryAttempts(30);
            comboPooledDataSource.setBreakAfterAcquireFailure(false);
            comboPooledDataSource.setTestConnectionOnCheckout(false);
            comboPooledDataSource.setAcquireRetryDelay(100);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }

        return comboPooledDataSource;
    }
}

定义事务管理平台

@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
    DataSourceTransactionManager dtm = new DataSourceTransactionManager();
    dtm.setDataSource(dataSource);
    return dtm;
}

事务的传播属性

  • 用来控制事务传输的策略,在一个请求内的事务回滚和提交;对比隔离级别则是不同请求的事务控制。

  • PROPAGATION_REQUIRED
    如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

  • PROPAGATION_SUPPORTS
    支持当前事务,如果当前没有事务,就以非事务方式执行。

  • PROPAGATION_MANDATORY
    使用当前的事务,如果当前没有事务,就抛出异常。

  • PROPAGATION_REQUIRES_NEW
    新建事务,如果当前存在事务,把当前事务挂起。

  • PROPAGATION_NOT_SUPPORTED
    以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  • PROPAGATION_NEVER
    以非事务方式执行,如果当前存在事务,则抛出异常。

  • PROPAGATION_NESTED
    如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

注解开启事务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • ConfigurationClassPostProcessor类支持了@ComponentScan、@Configuration、@Import、@ImportSource等注解,这个selectImports()方法在 ConfigurationClassParser类的569行调用
  • 这里把AutoProxyRegistrar和ProxyTransactionManagementConfiguration封装成beanDefinition对象

在这里插入图片描述

1. ProxyTransactionManagementConfiguration

在这里插入图片描述

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	/*
	* 创建事务切面实例
	* BeanFactoryTransactionAttributeSourceAdvisor
	*
	* */
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		//transactionAttributeSource()搜集@Transactional注解上设置的所有属性包装成对象,设置到advisor中
		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();
	}

	/*
	* 创建事务advice
	* TransactionInterceptor
	* */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		//这个TransactionInterceptor实现了MethodeInterceptor接口,到aop链式调用时,会调到里面的invoke()方法
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		//事务管理器要跟数据源挂钩,所以需要自己定义
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

2. TransactionInterceptor

在这里插入图片描述

  • 实现了MethodInterceptor,一定会有invoke()方法

在这里插入图片描述

3. ReflectiveMethodInvocation#proceed()

  • aop中,执行链式调用的代码

在这里插入图片描述
在这里插入图片描述

4. TransactionAspectSupport#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation)

  • 当程序运行带有@Transactional注解的方法时,就会调用到实现了MethodInterceptor接口的类的invoke()方法,最后会执行到这里,是事务的核心方法

在这里插入图片描述
在这里插入图片描述

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

	// If the transaction attribute is null, the method is non-transactional.
	// 1.获取事务属性类 AnnotationTransactionAttributeSource
	TransactionAttributeSource tas = getTransactionAttributeSource();

	// 2.获取方法上面有@Transactional注解的属性,包装成TransactionAttribute对象
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

	// 3.获取事务管理器
	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
	// 4.获取添加了@Transactional的方法名
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.	
		// 5.开启事务,根据不同的
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		Object retVal = null;
		try {
			// This is an around advice: Invoke the next interceptor in the chain.
			// This will normally result in a target object being invoked.
			// 6.火炬传递,会调用到被代理方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception
			// 7.事务回滚,rollback()
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			// 8.如果存在挂起的链接对象,重新绑定线程与连接对象的关系
			cleanupTransactionInfo(txInfo);
		}
		// 9.事务提交,commit()
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
	// 下面是编程式事务的处理方法,只有你自定义了一个CallbackPreferringPlatformTransactionManager类型的编程式事务才会走下面
	else {
		final ThrowableHolder throwableHolder = new ThrowableHolder();

		// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
		try {
			Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
				TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
				try {
					return invocation.proceedWithInvocation();
				}
				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);
				}
			});

			// Check result state: It might indicate a Throwable to rethrow.
			if (throwableHolder.throwable != null) {
				throw throwableHolder.throwable;
			}
			return result;
		}
		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;
		}
	}
}

5. TransactionAspectSupport#determineTransactionManager(@Nullable TransactionAttribute txAttr)

  • 获取事务管理器

在这里插入图片描述
在这里插入图片描述

  • 如果事务管理为空,先到缓存中找,如果缓存没有,再到beanFactory中找PlatformTransactionManager类的类,最后放到缓存中

在这里插入图片描述

6. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(), TransactionAspectSupport#createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification)

在这里插入图片描述
在这里插入图片描述

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) {
			//开启事务,这里重点看
			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);
}

7. AbstractPlatformTransactionManager#getTransaction(@Nullable TransactionDefinition definition)

在这里插入图片描述

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
	// 1.拿到DataSourceTransactionObject对象
	Object transaction = doGetTransaction();

	// Cache debug flag to avoid repeated checks.
	boolean debugEnabled = logger.isDebugEnabled();

	if (definition == null) {
		// Use defaults if no transaction definition given.
		definition = new DefaultTransactionDefinition();
	}

	// 2.第一次进来connectionHolder为空的,所以不存在事务
	if (isExistingTransaction(transaction)) {
		// Existing transaction found -> check propagation behavior to find out how to behave.
		return handleExistingTransaction(definition, transaction, debugEnabled);
	}

	// Check definition settings for new transaction.
	if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
		throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
	}

	// No existing transaction found -> check propagation behavior to find out how to proceed.
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		throw new IllegalTransactionStateException(
				"No existing transaction found for transaction marked with propagation 'mandatory'");
	}
	// 3.第一次进来大部分会走这里
	else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
			definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
			definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
		// 4.先挂起
		SuspendedResourcesHolder suspendedResources = suspend(null);
		if (debugEnabled) {
			logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
		}
		try {
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			// 5.创建事务状态对象,其实就是封装了事务对象的一些信息,记录事务状态的
			DefaultTransactionStatus status = newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

			// 6.开启事务,重点看看 DataSourceTransactionObject
			doBegin(transaction, definition);

			// 7.开启事务后,改变事务状态
			prepareSynchronization(status, definition);
			return status;
		}
		catch (RuntimeException | Error ex) {
			resume(null, suspendedResources);
			throw ex;
		}
	}
	else {
		// Create "empty" transaction: no actual transaction, but potentially synchronization.
		if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
			logger.warn("Custom isolation level specified but no actual transaction initiated; " +
					"isolation level will effectively be ignored: " + definition);
		}
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
	}
}

8. DataSourceTransactionManager#doGetTransaction()

在这里插入图片描述
在这里插入图片描述

  • DataSourceTransactionObject 为事务对象,用来管理连接对象Connection
protected Object doGetTransaction() {
	// 1.管理connection对象,创建回滚点,按照回滚点回滚,释放回滚点
	DataSourceTransactionObject txObject = new DataSourceTransactionObject();

	// 2.DataSourceTransactionManager默认是允许嵌套事务的
	txObject.setSavepointAllowed(isNestedTransactionAllowed());

	// 3.obtainDataSource() 获取数据源对象,其实就是数据库连接块对象
	ConnectionHolder conHolder =
			(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}
  • 从ThreadLocal中拿到连接对象,方便在嵌套事务中,拿到同一个连接

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),DataSourceTransactionManager#doBegin(Object transaction, TransactionDefinition definition)

在这里插入图片描述
在这里插入图片描述

protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		// 1.如果没有数据库连接
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			// 2.从连接池里面获取连接
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			// 3.把连接包装成ConnectionHolder,然后设置到事务对象中
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}

		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		con = txObject.getConnectionHolder().getConnection();

		// 4.从数据库连接中获取隔离级别
		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);

		// 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).
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			// 5.关闭连接的自动提交,其实这步就是开启了事务
			con.setAutoCommit(false);
		}

		//设置只读事务 从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!
		//设置只读事务就是告诉数据库,我这个事务内没有新增,修改,删除操作只有查询操作,不需要数据库锁等操作,减少数据库压力
		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()) {
			// 6.如果是新创建的事务,则建立当前线程和数据库连接的关系
			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);
	}
}

在这里插入图片描述

  • 建立连接池和连接对象的映射关系
  • 建立用户线程和map的映射关系,后面通过用户线程可以拿到一个唯一的连接

在这里插入图片描述

  • 开启事务最主要的操作就是关闭自动提交

10. 回到第7步 AbstractPlatformTransactionManager#getTransaction(),AbstractPlatformTransactionManager#handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)

在这里插入图片描述

  • 如果是一个线程运行了第二个带有@Transactional注解的方法就走到handleExistingTransaction()方法

在这里插入图片描述

  • 第二次进来connectionHolder不为空,进入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'");
	}

	//以非事务方式执行操作,如果当前存在事务,就把当前事务挂起(可以不看)
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
		if (debugEnabled) {
			logger.debug("Suspending current transaction");
		}
		//挂起当前事务
		Object suspendedResources = suspend(transaction);
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
		//修改事务状态信息,把事务的一些信息存储到当前线程中,ThreadLocal中
		return prepareTransactionStatus(
				definition, null, false, newSynchronization, debugEnabled, suspendedResources);
	}
	// 1.新建事务,如果当前存在事务,把当前事务挂起
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
		if (debugEnabled) {
			logger.debug("Suspending current transaction, creating new transaction with name [" +
					definition.getName() + "]");
		}
		// 2.挂起,解除旧的连接对象与线程的绑定关系,并把旧的连接对象包装到SuspendedResourcesHolder中
		SuspendedResourcesHolder suspendedResources = suspend(transaction);
		try {
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			// 事务状态设置为true,表示是一个新的事务
			DefaultTransactionStatus status = newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
			// 3.开启事务(这是一个新的事务)
			doBegin(transaction, definition);
			prepareSynchronization(status, definition);
			return status;
		}
		catch (RuntimeException | Error beginEx) {
			resumeAfterBeginException(transaction, suspendedResources, beginEx);
			throw beginEx;
		}
	}
	// 4.如果当前存在事务,则在嵌套事务内执行,嵌套事务没有做挂起操作,所以用的是同一个连接对象connection
	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.
			// 事务状态设置为false
			DefaultTransactionStatus status =
					prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
			// 5.在执行被代理方法前,创建回滚点
			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.
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			DefaultTransactionStatus status = newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, null);
			doBegin(transaction, definition);
			prepareSynchronization(status, definition);
			return status;
		}
	}

	// 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);
	// 4.如果传播属性是PROPAGATION_REQUIRED,上面的if,else都不会进,直接返回下面这个结果
	// 特别要注意的是这里把事务的状态设置为了false,但是第一次进来的时候,事务状态被设置为了true
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

  • 第一次进getTransaction()得到的事务状态,true(表示是新的事务)

在这里插入图片描述

  • 如果传播属性是PROPAGATION_REQUIRED,则第二次进getTransaction()得到的事务状态,false(说明不是新的事务)

在这里插入图片描述

  • 如果传播属性是PROPAGATION_REQUIRES_NEW,则第二次进getTransaction()得到的事务状态,true(说明是新的事务)

在这里插入图片描述

  • PROPAGATION_REQUIRED连接对象是同一个,事务对象DataSourceTransactionObject 不是同一个。
  • PROPAGATION_REQUIRES_NEW连接对象也不是同一个(把旧的挂起了),事务对象DataSourceTransactionObject 也不是同一个。
  • 事务对象DataSourceTransactionObject 每次都会new一个新的。

11. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex)

  • 事务回滚

在这里插入图片描述

  • 把事务状态属性对象传进来

在这里插入图片描述
在这里插入图片描述

  • 只有事务状态是true的才会进入if,走事务回滚方法doRollback(status)

在这里插入图片描述
在这里插入图片描述

12. 回到第4步,TransactionAspectSupport#invokeWithinTransaction(),TransactionAspectSupport#commitTransactionAfterReturning(@Nullable TransactionInfo txInfo)

  • 事务提交

在这里插入图片描述

  • 把事务对象的状态属性对象传进来

在这里插入图片描述

  • 走到此方法最后一行代码

在这里插入图片描述
在这里插入图片描述

  • 嵌套事务情况,存在回滚点,则进入if,然后删除回滚点

在这里插入图片描述

  • 如果是进入第一个加了@Transactional的方法,且传播属性是PROPAGATION_REQUIRED时,要么不存在回滚点,或者嵌套事务的回滚点都被删除了,肯定会走下面代码,判断事务状态,如果是true(表示是新的事务),进入if,会走到事务提交方法doCommit(status),把所有的事务都提交

在这里插入图片描述

  • 由此可见,只有事务状态是true的事务才能提交

在这里插入图片描述

案例分析

1. 场景一

  • 3个方法的事务传播属性都是REQUIRED
  @Transactional(propagation = Propagation.REQUIRED)
    public void transation() {
        transationService.getTicket();
        transationService.getTicketModeOne();
    }

    @Transactional
    public int getTicket() {
        return 0;
    }

    @Transactional
    public int getMoney() {
        return 0;
    }
  • 模拟事务关系
public void transation() {
    try{
        try{
            getTicket();
        }catch (Exception e){
            ticketRollBack();
            throw e;
        }
        ticketCommit();

        try{
            getMoney();
        }catch (Exception e){
            moneyRollBack();
            throw e;
        }
        moneyCommit();
    }catch (Exception e){
        transationRollBack();
        throw e;
    }
    transationCommit();
}
  • 如果getTicket()方法发生异常,则进入catch,因为传播属性是REQUIRED,所以getTicket方法的事务状态是false,不会走ticketRollBack()方法回滚;因此抛出异常,被transation方法的cathc捕获,而且transation方法的事务状态是true,所以会走transationRollBack()回滚;
  • 如果是getMoney()方法发生异常,和前面的结果是一样的,走transationRollBack()回滚;
  • 最终结果是,getTicket()和getMoney()都不会改变数据库内的数据。

2. 场景二

  • getTicket方法的事务传播属性是REQUIRES_NEW,其他为REQUIRED
  @Transactional(propagation = Propagation.REQUIRED)
    public void transation() {
        transationService.getTicket();
        transationService.getTicketModeOne();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int getTicket() {
        return 0;
    }

    @Transactional
    public int getMoney() {
        return 0;
    }
  • 模拟事务关系
public void transation() {
    try{
        try{
            getTicket();
        }catch (Exception e){
            ticketRollBack();
            throw e;
        }
        ticketCommit();

        try{
            getMoney();
        }catch (Exception e){
            moneyRollBack();
            throw e;
        }
        moneyCommit();
    }catch (Exception e){
        transationRollBack();
        throw e;
    }
    transationCommit();
}
  • 如果getTicket()方法发生异常,则进入catch,因为传播属性是REQUIRES_NEW,所以getTicket方法的事务状态是true,会走ticketRollBack方法进行回滚;走到外层catch,但是transationRollBack方法不会回滚,但是getMoney方法也没有执行,所以最终结果是,getTicket和getMoney都不会改变数据库内的数据;
  • 如果是getMoney()方法发生异常,则getTicket()会正常执行,而且会走ticketCommit()提交事务,因为getTicket的事务状态是true,而getMoney方法的异常,最终会被最外层的catch捕获,走transationRollBack方法回滚,所以最终结果是,getTicket方法改变了数据库内的数据,而getMoney方法没有改变数据库内的数据

3. 场景三

  • getTicket和getMoney方法的事务传播属性是REQUIRES_NEW,transation为REQUIRED
  @Transactional(propagation = Propagation.REQUIRED)
    public void transation() {
        transationService.getTicket();
        transationService.getTicketModeOne();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int getTicket() {
        return 0;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int getMoney() {
        return 0;
    }
  • 模拟事务关系
public void transation() {
    try{
        try{
            getTicket();
        }catch (Exception e){
            ticketRollBack();
            throw e;
        }
        ticketCommit();

        try{
            getMoney();
        }catch (Exception e){
            moneyRollBack();
            throw e;
        }
        moneyCommit();
    }catch (Exception e){
        transationRollBack();
        throw e;
    }
    transationCommit();
}
  • 如果getTicket()方法发生异常,则进入catch,走ticketRollBack回滚,再到最外层catch,getMoney方法没有执行,最终结果是getTicket和getMoney都没改变数据;
  • 如果是getMoney发生异常,则getTicket改变了数据,但是getMoney没有改变数据。
  • 注意: 以上的异常都是被spring捕获的,如果你自己在业务方法内加了try-catch,发生的异常被方法本身吞掉了,spring是捕获不到异常的,也就不会走到回滚方法

4. 场景四

  • getTicket和getMoney方法的事务传播属性是PROPAGATION_NESTED(可以按照回滚点回滚),transation为REQUIRED,希望getTicket或getMoney发生异常,各自按照回滚点回滚,而不影响其他方法对数据的改变
  @Transactional(propagation = Propagation.REQUIRED)
    public void transation() {
        transationService.getTicket();
        transationService.getTicketModeOne();
    }

    @Transactional(propagation = Propagation.PROPAGATION_NESTED)
    public int getTicket() {
        return 0;
    }

    @Transactional(propagation = Propagation.PROPAGATION_NESTED)
    public int getMoney() {
        return 0;
    }
  • 模拟事务关系
public void transation() {
    try{
        try{
            getTicket();
        }catch (Exception e){
            ticketRollBack();
            throw e;
        }
        ticketCommit();

        try{
            getMoney();
        }catch (Exception e){
            moneyRollBack();
            throw e;
        }
        moneyCommit();
    }catch (Exception e){
        transationRollBack();
        throw e;
    }
    transationCommit();
}
  • getTicket()正常执行,ticketCommit()删除回滚点,但是getMoney()方法发生异常,则进入catch,走moneyRollBack按照回滚点回滚,再到最外层catch,走transationRollBack方法全部回滚,最终结果是getTicket和getMoney都没改变数据,与各自按照回滚点回滚,而不影响其他方法对数据的改变的目标不一致
  • 解决方法:在transation方法内部加try-catch,把内部异常吞掉,不被transation方法的spring的catch捕获到,就不会全部回滚
@Transactional(propagation = Propagation.REQUIRED)
public void transation() {

    try {
        transationService.getTicket();
        transationService.getMoney();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值