TransactionInterceptor声明式学习总结

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

事务学习中TransactionInterceptor增强方法的处理逻辑太过复杂,这里单独对其


一、原始Demo

看看没有Spring之前,如果需要事务的控制代码大概是这样的

public class JDBCDemo {
    public static void main(String[] args) throws Exception {
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        //连接
        String url = "jdbc:mysql://127.0.0.1:3306/db1?useSSL=false";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);

        //定义sql
        String sql1 = "insert into stu(name, id) values ('zhangsan', 3);";
        String sql2 = "insert into stu(name, id) values ('lisi', 4);";
        //获取执行sql的对象
        Statement stmt = conn.createStatement();
        try{
            //相当于开启事务
            conn.setAutoCommit(false);
            //执行两次事务
            stmt.executeUpdate(sql1);
            stmt.executeUpdate(sql2);
            //事务提交
            conn.commit();
        }catch (Exception e){
            //如果出错就回滚
            conn.rollback();
            e.printStackTrace();
        }
        //释放资源
        stmt.close();
        conn.close();
    }
}

大致流程如下
1 获取连接,并关闭连接的自动提交(因为要保证所有sql执行完毕后 一起提交)
2 执行业务处理(各种sql执行)
3 后置处理,如果出现异常(rollback回滚),如果成功(commit提交)。提交和回滚都是通过conn对象执行的
4 释放连接

其实我们只想关心业务处理部分,Spring基于AOP的方式帮我们做了优化,将与事务相关的代码隐藏于切面中。Spring使用TransactionInterceptor(本质是一个Advice)对所有@Transactional注释的方法进行增强。
在这里插入图片描述
看看这个类的核心方法invokeWithinTransaction,核心方法由其父类实现

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		   //响应式变成事务处理 5.2版本后新增的 这里没学过 跳过了
		}
		//获取事务管理器【DataSourceTransactionManager】
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		//声明式事务处理 重点看这个
		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			//创建事务对象
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				//执行业务代码
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				//执行回滚处理
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
            ...
			//执行提交处理
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		else {
			//编程式事务处理 没过过 跳过了
		}
	}

主要有三个分支,响应式变成事务处理、声明式事务处理、编程式事务处理。这里主要总结声明式事务处理,其他两个超纲了没学过。

大致流程与原始demo对比

  • 创建事务对象,原始Demo中获取的是数据库连接对象
  • 执行业务处理,原始Demo中执行的sql语句也相当于业务处理
  • 后置处理,如果出现异常(回滚处理),如果成功(提交处理),原始Demo中异常直接调用连接对象进行回滚,提交也是直接连接对象提交
  • 没有释放连接的步骤,因为用了连接池

可以发现虽然主流程及其相似,其实事务对象中就包含数据库连接、后置处理中回滚处理最终调用的就是连接的回滚,提交处理也是调用了连接的提交。那为什么spring对每个步骤都做了封装呢?因为spring除了帮我们实现了事务的基本操作(提交、回滚),还帮我们实现了事务的传播性

二、事务的传播性简介

假如某个service有三个方法,每个方法都有自己的事务

@Service
public class SubService {
    @Transactional
    public void a(){
        //do some
    }
    @Transactional
    public void b(){
        //do some
    }
    @Transactional
    public void c(){
        //do some
    }
}

现在有另一个service的方法,如下

@Service
public class ActiveService {
    @Autowired
    private SubService subService;
    public void active(){
        subService.a();
        subService.b();
        subService.c();
    }
}

最终结果应该是什么样的呢?或者说运行结果是什么样的比较合理。我开始认为要么都成功要么都失败比较合理。其实不然,例举下几个业务场景

  • 场景一 方法a和方法b必须保证一起成功或者失败,方法c可以成功也可以失败其失败并不影响其他方法。
  • 场景二 方法a和方法b执行成功,方法c执行失败时全部回滚(这个感觉是我开始任务比较合理的结果)
  • 场景三 a和方法b执行成功,方法c执行失败时。只有方法c回滚,其他两个方法正常提交(部分回滚模式)

根据业务需要其实还有很多种场景,那么如何让方法的执行按照我们的想法来执行呢?这就要用到事务的传播性了。

事务的传播性一共有七种

  • PROPAGATION_REQUIRED 支持当前事务;如果不存在,则创建一个新的 (spring默认传播)
  • PROPAGATION_SUPPORTS 支持当前事务;如果不存在,则以非事务方式执行
  • PROPAGATION_MANDATORY 支持当前事务;如果当前不存在事务,则抛出异常
  • PROPAGATION_REQUIRES_NEW 创建一个新事务,如果存在则挂起当前事务
  • PROPAGATION_NOT_SUPPORTED 不支持当前事务;而是始终以非事务方式执行
  • PROPAGATION_NEVER 不支持当前事务;如果当前事务存在,则抛出异常
  • PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行,否则行为类似于PROPAGATION_REQUIRED

上边的解释是基于spring源码翻译的,下边是我个人的理解。事务的保证本质上是靠数据库连接来完成的,那么下边我先暂且把事务称为数据库连接。方法执行必然是有线程来完成的,那么我把线程也引入进来这样比较好说明

  • PROPAGATION_REQUIRED 如果当前线程持有数据库连接那就用当前数据库连接进行业务数据处理,反之就从连接池中获取一个并和当前线程进行绑定。 (spring默认传播)
  • PROPAGATION_SUPPORTS 如果当前线程持有数据库连接那就用当前数据库连接进行业务数据处理,反之数据库连接随用随取
  • PROPAGATION_MANDATORY 如果当前线程持有数据库连接那就用当前数据库连接进行业务数据处理,反之抛异常。也就是说这种传播性的方法必须得有事务。
  • PROPAGATION_REQUIRES_NEW 如果当前线程持有数据库连接就先找个地方把连接缓存起来(这个操作叫挂起),然后重新向连接池申请一个连接和当前线程绑定完成业务数据处理,最后再将缓存得连接拿出来从新和当前线程绑定(这个操作叫恢复)。反之就是没有挂起和修复操作
  • PROPAGATION_NOT_SUPPORTED 如果当前线程持有数据库连接就先找个地方把连接缓存起来(这个操作叫挂起),然后处理业务期间数据库连接随用随取,最后再将缓存得连接拿出来从新和当前线程绑定(这个操作叫恢复)。反之就是没有挂起和修复操作
  • PROPAGATION_NEVER 如果当前线程持有数据库连接直接抛异常。反之数据库连接随用随取。也就是说这种传播性的方法必须不能有事务。
  • PROPAGATION_NESTED 如果当前线程持有数据库连接那就用当前数据库连接进行业务数据处理,在方法业务处理前先设置一个保存点,如果业务执行成功释放保存点,否则回滚到保存点。刚刚举例中的场景3就非常适合用这种传播性

上边提到了两种连接,一种是和线程绑定的一种是随用随取。两者区别就是,前者连接相当于交给了spirng来控制,spring为了控制事务会关闭其自动提交的能力,后者连接是由连接池控制的,一般都是自动提交即执行sql立刻提交入库也就不会保证事务了。

三、源码总结

接下来要跟源码了,跟之前先了解几个核心类。方便源码的阅读

3.1、核心对象简介

类名简介
ConnectionHolder数据库连接持有者,该对象会和线程绑定
主要属性
1 currentConnection 数据库连接
2 transactionActive 持有者是否可用
3 rollbackOnly 回滚标识,在进行提交处理时会判断该标识,如果为true会进入回滚处理流程
DataSourceTransactionObjectConnectionHolder的封装类
主要属性
1 connectionHolder 上边的连接持有者对象
2 newConnectionHolder 内部的连接持有者是不是新的
TransactionStatus事务状态对象 sping将事务传播性的处理结果统一封装在其中,后续事务管理器使用该对象进行事务的提交或者回滚处理
主要属性
1 transaction 上边的连接持有者的封装类
2 newTransaction 当前事务是不是新事务
3 suspendedResources 挂起的事务信息
4 savepoint 保存点对象
AbstractPlatformTransactionManager事务管理器父类,基于事务处理的各个主流程提供了统一的抽象方法,细节由子类实现。
主要api
1 getTransaction() 获取事务状态对象TransactionStatus ,这里完成了对事务传播性的统一处理
2 suspend() 挂起事务
3 resume() 修复事务
4 commit(TransactionStatus status)提交事务 细节子类实现
5 rollback(TransactionStatus status)提交回滚
DataSourceTransactionManager事务管理器 spring中使用的事务管理器该类是AbstractPlatformTransactionManager的子类,主要用于针对数据库的事务控制
主要api
1 obtainDataSource()获取数据源
2 doGetTransaction()构建并返回DataSourceTransactionObject
3 doBegin()主要用于初始化DataSourceTransactionObject内部的ConnectionHolder
4 doSuspend()挂起事务对父类细节的实现
5 doResume()修复事务对父类细节的实现
6 doCommit()提交事务对父类细节的实现
7 doRollback()回滚事务对父类细节的实现
8 doSetRollbackOnly()设置ConnectionHolder中的rollbackOnly属性
9 isExistingTransaction()是否预先存在事务
TransactionInfo事务上下文 保存事务处理所需要的全部数据
主要属性
1 transactionManager 事务管理器
2 transactionStatus 事务状态对象
TransactionSynchronizationManager线程绑定数据管理器 之前提到的和线程绑定的数据都保存在其中
主要属性
1 resources 一个map对象,key是数据源,value是ConnectionHolder
2 synchronizations 一个set集合 一般通过set集合是否为空来判断线程的事务同步是否被激活
SuspendedResourcesHolder挂在类 用于挂载与当前线程绑定的数据,挂载后DataSourceTransactionManager的属性基本上都会被还原
主要属性
1 suspendedResources 本质就是原来的ConnectionHolder

3.2、主流程方法invokeWithinTransaction

基于AOP源码分析其入口方法就是invoke方法

public Object invoke(MethodInvocation invocation) throws Throwable {
	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
	//主要执行逻辑入口 该方法由其父类实现
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

进入核心方法,刚刚提到过这个方法。这里就是对整体流程的控制了

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		   //响应式变成事务处理 5.2版本后新增的 这里没学过 跳过了
		}
		//获取事务管理器【DataSourceTransactionManager】
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		//声明式事务处理 重点看这个
		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			//创建事务上下文对象
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				//执行业务代码
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				//执行回滚处理
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
            ...
			//执行提交处理
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		else {
			//编程式事务处理 没过过 跳过了
		}
	}

大致流程如下

  • 获取事务上下文对象createTransactionIfNecessary() 这里主要完成了TransactionStatus对象的构建,也就是针对传播性的处理
  • 执行业务处理 invocation.proceedWithInvocation() aop的知识 会执行我们的业务代码
  • 异常时进行回滚处理 completeTransactionAfterThrowing 回滚处理
  • 正常请跨下进行提交处理 commitTransactionAfterReturning 提交处理

接下来逐个跟踪下

3.2.1、Spring事务传播性的处理

先大致介绍下spring对事务传播的处理逻辑,方便后续的源码跟踪

  • 1 原来不存在事务(线程未绑定数据库连接),各个传播性会有3种处理方式

    • 创建新事务【PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED】
    • 抛异常【PROPAGATION_MANDATORY】
    • 啥也不干【PROPAGATION_SUPPORTS 、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER】
  • 2 原来存在事务(线程绑定了数据库连接),各个传播性会有4种处理方式

    • 使用原来事务【PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY】
    • 使用原来的事务,并且创建保存点【PROPAGATION_NESTED】
    • 抛异常【PROPAGATION_NEVER】
    • 挂起【PROPAGATION_NOT_SUPPORTED】
    • 挂起后新建一个【PROPAGATION_REQUIRES_NEW】

接着跟源码

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

		//封装txAttr
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}
		//构建TransactionStatus对象
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				status = tm.getTransaction(txAttr);
			}
			else {
				...
			}
		}
		//构建TransactionInfo对象
		//将事务相关的对象统一封装成TransactionInfo
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

这里最终将4个对象封装成TransactionInfo并返回,其中前三个对象基本上就是入参。所以该方法主重要是构建了TransactionStatus对象。这个对象中封装了事务传播性的处理结果。为什么这么说呢?那需要跟下**AbstractPlatformTransactionManager.getTransaction()**方法

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {
        -------------------------获取事务属性-------------------------------------------------   
		//这里封装了方法上@Transactional中的属性
		//其中propagation属性就是事务的传播性,默认是Propagation.REQUIRED
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
		//获取【DataSourceTransactionObject】 其内部持有连接
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

       -------------------------之前存在事务-传播性处理-------------------------------------------------   
		//如果已经存在一个事务 基于handleExistingTransaction方法构建TransactionStatus
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}
		
		-------------------------之前不存在事务-传播性处理-------------------------------------------------   
		...
		//如果事务传播性是PROPAGATION_MANDATORY,基于该传播特性 这里抛出异常【必须有事务但是却没有】
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		//如果事务传播性是【PROPAGATION_REQUIRED 、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED】
		//基于startTransaction方法构建TransactionStatus
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			//挂起一个null 本质上什么都没干 后续根这里可以看下	
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		//如果是其他得传播性【PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER】
		//基于prepareTransactionStatus方法构建TransactionStatus
		else {
			...
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

该方法的主要目的就是处理事务传播性并将结果封装到TransactionStatus对象中。

主要流程如下

  • 获取TransactionDefinition,其内部封装了@Transactional中的属性。其中包括事务的传播性定义,默认是PROPAGATION_REQUIRED
  • 构建DataSourceTransactionObject通过doGetTransaction()
  • 如果之前存在事务,通过**handleExistingTransaction()**方法处理传播性
  • 如果之前不存在事务,在本方后半段完成了传播性的处理

开始对spring事务传播性简介其实说的就是这里,接下来按照是否存在事务两个分支来看看事务传播性的处理逻辑

3.2.1.1、构建DataSourceTransactionObject

重点跟doGetTransaction方法,该方法在DataSourceTransactionManager中实现

protected Object doGetTransaction() {
		//简单除暴 直接new
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		//通过TransactionSynchronizationManager对象获取ConnectionHolder
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		//设置txObject
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
}

该方法首先直接构建了DataSourceTransactionObject 对象,然后去TransactionSynchronizationManager中获取ConnectionHolder,首次返回肯定是null。这里大致总结下DataSourceTransactionObject的结构
首次
在这里插入图片描述

非首次
在这里插入图片描述

非首次时connectionHolder时什么时候被放到TransactionSynchronizationManager中的呢?后边会介绍

3.2.1.2、当前不存在事务-事务传播性的处理

不存在事务,事务传播性的处理代码如下

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
		...//如果事务传播性是PROPAGATION_MANDATORY,基于该传播特性 这里抛出异常【必须有事务但是却没有】
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		//如果事务传播性是【PROPAGATION_REQUIRED 、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED】
		//基于startTransaction方法构建TransactionStatus
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			//挂起一个null 本质上什么都没干 后续根这里可以看下	
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		//如果是其他得传播性【PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER】
		//基于prepareTransactionStatus方法构建TransactionStatus
		else {
			...
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}
3.2.1.2.1、PROPAGATION_MANDATORY处理方式

类型直接抛出异常

throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
3.2.1.2.2、【PROPAGATION_SUPPORTS 、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER】处理方式
protected final DefaultTransactionStatus prepareTransactionStatus(
			TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
			boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
		//构建TransactionStatus
		//参数transaction 为null
		//参数newTransaction 为true
		//参数suspendedResources 为null
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
		prepareSynchronization(status, definition);
		return status;
	}

这里直接构建了TransactionStatus,这里重点关注的是其内部的3个构造参数

3.2.1.2.3、【PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED】 处理方式

处理主要逻辑在startTransaction()中,在看startTransaction()之前先简单看下suspend(null),这个方法很重要,但是在本次调用中什么都没干,这里先简单过下

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
	//if判断条件TransactionSynchronizationManager.isSynchronizationActive()会返回false
	//TransactionSynchronizationManager这个对象相当于线程的数据库 各种和线程绑定的数据都放这里了
	if (TransactionSynchronizationManager.isSynchronizationActive()) {
		List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
		try {
			Object suspendedResources = null;
			if (transaction != null) {
				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);
			return new SuspendedResourcesHolder(
					suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
		}
		catch (RuntimeException | Error ex) {
			// doSuspend failed - original transaction is still active...
			doResumeSynchronization(suspendedSynchronizations);
			throw ex;
		}
	}
	//入参是null 这个分支不会走
	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;
	}
}

为什么TransactionSynchronizationManager.isSynchronizationActive()返回false呢,看下其代码

public static boolean isSynchronizationActive() {
	return (synchronizations.get() != null);
}

synchronizations默认是个空集合,所以这里返回了false。那么什么时候会是非空呢?,后边来介绍
虽然在本次调用中什么都没干,但是这个方法非常重要。这个是事务的挂起方法,后边还会遇到他。这里不展开总结了。

进入重点方法startTransaction()

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

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		//这里直接new 关键参数介绍
		//第二个参数 transaction (3.2.1.1、doGetTransaction 构建的DataSourceTransactionObject对象) 
		//第三个参数 boolean 标识当前DefaultTransactionStatus是一个新事务
		//最后一个参数 suspendedResources 用于保存挂起对象 这里刚刚分析过了 首次进入该值是null
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		//一切的开始
		doBegin(transaction, definition);
		//将线程中需要的参数保存到TransactionSynchronizationManager
		prepareSynchronization(status, definition);
		return status;
}

首先这里直接构建了TransactionStatus,这里重点关注的是其内结构
在这里插入图片描述

然后看下doBegin方法

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

		try {
			//之前分析过首次DataSourceTransactionObject中没有ConnectionHolder
			//所以会进入创建分支
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				//通过数据源获取一条数据库连接	
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				//将连接封装到ConnectionHolder对象中
				//在将ConnectionHolder封装到DataSourceTransactionObject中,并且设置ConnectionHolder是新的
				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());

			//连接提交交给spring来管理
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			prepareTransactionalConnection(con, definition);
			//设置ConnectionHolder是连接激活状态 
			//3.2.1.2中判断是否是否存在 (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive())就用到了这个属性
			txObject.getConnectionHolder().setTransactionActive(true);

			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			//首次ConnectionHolder一定是新的
			if (txObject.isNewConnectionHolder()) {
			    //将数据源和ConnectionHolder绑定,并将绑定关系保存到TransactionSynchronizationManager中
				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);
		}
	}

这里信息量很大,与前面的很多地方相呼应了

  • 首先是ConnectionHolder的创建,以及ConnectionHolder对象中数据库连接的获取
  • 数据库连接交给spring管理,不会自动提交了
  • ConnectionHolder绑定到线程TransactionSynchronizationManager中

总结DataSourceTransactionObject最终的数据结构如下
在这里插入图片描述

最后看下prepareSynchronization方法

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
		//刚刚分析了构造TransactionStatus是第三个参数是true 所以会进入这个if块
		if (status.isNewSynchronization()) {
			TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
					definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
							definition.getIsolationLevel() : null);
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
			TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
			//初始化其synchronizations属性,为其内部放了一个空集合
			TransactionSynchronizationManager.initSynchronization();
		}
}

看下initSynchronization方法

if (isSynchronizationActive()) {
			throw new IllegalStateException("Cannot activate transaction synchronization - already active");
		}
		logger.trace("Initializing transaction synchronization");
		//这里可以看到synchronizations集合被赋值了
		synchronizations.set(new LinkedHashSet<>());

这里可以看到synchronizations集合被赋值了,也就是说下次在执行挂起方式**suspend()**时会进入到if代码块了

到这里最终总结下startTransaction方法返回的TransactionStatus对象数据格式
在这里插入图片描述
附带两个关键条件
1 再次实行挂起方法会进入if语句块了
2 TransactionSynchronizationManager中绑定了ConnectionHolder

3.2.1.3、当前存在事务-事务传播性的处理

重新getTransaction方法,这次看事务存在时的处理逻辑

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {
        -------------------------获取事务属性-------------------------------------------------   
		//这里封装了方法上@Transactional中的属性
		//其中propagation属性就是事务的传播性,默认是Propagation.REQUIRED
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
		//获取【DataSourceTransactionObject】 其内部持有连接
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

       -------------------------之前存在事务-传播性处理-------------------------------------------------   
		//如果已经存在一个事务 基于handleExistingTransaction方法构建TransactionStatus
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}
		
		-------------------------之前不存在事务-传播性处理-------------------------------------------------   
		...}

首先看**doGetTransaction()**方法

protected Object doGetTransaction() {
		//简单除暴 直接new
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		//通过TransactionSynchronizationManager对象获取ConnectionHolder
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		//设置txObject
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
}

和之前不同,这次的conHolder非空。那么DataSourceTransactionObject的数据结构如下
在这里插入图片描述

接着看下**isExistingTransaction(transaction)**方法,判断是否存在事务。方法在DataSourceTransactionManager中实现

protected boolean isExistingTransaction(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		//可以发现刚刚分析了**startTransaction**方法产生的DefaultTransactionStatus对象 刚好符合条件
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}

我现在的理解是只要执行过startTransaction方法,那么isExistingTransaction返回结果一定为true

看核心方法handleExistingTransaction()

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
		//PROPAGATION_NEVER方式直接抛异常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}
		//PROPAGATION_NOT_SUPPORTED 先挂起然后构建一个事务为空的TransactionStatus
		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);
		}
		//PROPAGATION_REQUIRES_NEW 先挂起然后通过startTransaction构建TransactionStatus
		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;
			}
		}
		//PROPAGATION_NESTED 处理方式 直接使用原来的transaction 并且创建保存点
		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);
		//PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY 直接使用原来的transaction
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

这里可以发现,和之前不存在事务的处理方式差不多。还是基于不同的传播性来生成TransactionStatus。

这次重点看下挂起**suspend()**方法,因为其他方法之前基本都分析过了

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
	//这一次会进入if分支 之前分析过了
	//这次transaction非空,数据结构上边有
	if (TransactionSynchronizationManager.isSynchronizationActive()) {
		List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
		try {
			Object suspendedResources = null;
			if (transaction != null) {
				//这里会返回 之前和线程绑定的ConnectionHolder
				suspendedResources = doSuspend(transaction);
			}
			//将当前TransactionSynchronizationManager中的数据提取出来 挂在到SuspendedResourcesHolder对象中
			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);
			//这类可以看到原来的ConnectionHolder 也会被挂在到SuspendedResourcesHolder对象中
			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;
	}
}

跟下doSuspend方法,该方法在DataSourceTransactionManager中实现

protected Object doSuspend(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		txObject.setConnectionHolder(null);
		return TransactionSynchronizationManager.unbindResource(obtainDataSource());
	}

可以发现这里主要就是将原来的ConnectionHolder和线程解绑,并将ConnectionHolder返回。
挂起对象的数据结构
在这里插入图片描述

这里总结下挂载方法,其最终结果是将原来与线程绑定的ConnectionHolder,还有之前与线程绑定的其他参数统一挂在到SuspendedResourcesHolder对象中。并将TransactionSynchronizationManager还原成初始状态。最终目的让有事务状态变为无事务状态
下边跟下各个分支的处理

3.2.1.3.1、PROPAGATION_NEVER处理方式

直接抛异常

throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
3.2.1.3.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);
		}

先挂载,然后通过**prepareTransactionStatus()**方法构建空事务,核心方法都分析过了,直接给出TransactionStatus最终的数据结构
在这里插入图片描述
附带TransactionSynchronizationManager中没有ConnectionHolder了

3.2.1.3.3、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;
			}

先挂载事务,然后调用startTransaction构建一个新事务,核心方法之前都分析过了。最终数据结构如下
在这里插入图片描述

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

创建保存点**createAndHoldSavepoint()**之前没看过 重点跟下这里

public void createAndHoldSavepoint() throws TransactionException {
		//通过保存点管理器获取保存点 最终保存到status对象的savepoint属性中
		//getSavepointManager()这个方法最终返回的其实是DataSourceTransactionObject 
		//最终使用DataSourceTransactionObject中的ConnectionHolder中的数据库连接 创建的保存点对象
		setSavepoint(getSavepointManager().createSavepoint());
	}

这个方法不展开跟了,总结就是拿数据库连接创建了一个保存点对象将其封装到了DefaultTransactionStatus里。
DefaultTransactionStatus 最终数据结构
在这里插入图片描述

3.2.1.3.3、【PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY】处理方式
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

DefaultTransactionStatus 最终数据结构
在这里插入图片描述

到这里事务传播各种情况生成DefaultTransactionStatus都已经总结完了

3.2.1.4、事务传播性处理结果总结

这里把各个分支下DefaultTransactionStatus数据结构统一整理下
在这里插入图片描述
最终将TransactionStatus封装进TransactionInfo对象中,到这里 createTransactionIfNecessary方法基本分析完了,主要处理事务的传播性。后续的提交和回滚处理都需要用到TransactionStatus对象。接下来看看提交和回滚的处理方式

3.2.2、回滚处理

异常回滚处理逻辑分析

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);
			}
			//第二个判断条件展开如下return (ex instanceof RuntimeException || ex instanceof Error);
			//可以看出只有RuntimeException和Error才能执行回滚逻辑
			if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
			        //使用任务管理器和TransactionStatus执行回滚操作
					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;
				}
			}
		}
	}
  • 首先看是否具备回滚条件,要保证TransactionStatus非空。之前分析过这个对象不能为空
  • 只有RuntimeException和Error才能执行回滚逻辑
  • 最后调用事务管理器的rollback方法回滚,继续跟这里
public final void rollback(TransactionStatus status) throws TransactionException {
		//如果状态是已完成 直接抛出异常 
		//status在提交或者回滚时会被标记为已完成 保证一个status对象只能提交或者回滚一次
		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);
				//有没有保持点 如果有回滚到保存点
				//之前分析中没有创建过保存点 不会进入该分支
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to 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()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							//之前有事务 不执行回滚 设置一个回滚标识
							//最终回滚标识被设置到了 其内部的ConnectionHolder对象的rollbackOnly属性中
							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);
		}
	}

rollback方法

  • rollback方法主要判断TransactionStatus是否已完成,防止重复提交或者回滚
  • 处理回滚方法交给processRollback方法继续处理

processRollback方法

  • 如果有保存点,之前分析过【有事务并且当前传播性是NESTED时,才会有保存点】。回滚到保存点
  • 如果是新事务,【之前无事务的REQUIRED、REQUIRES_NEW、NESTED】、【之前有事务的REQUIRES_NEW】都是新事务。通过doRollback方法直接执行回滚。方法内就是调用连接对象回滚所以不在跟进了
  • 如果不是新事务执行doSetRollbackOnly(),不在跟进了,这里简述下其作用是给TransactionStatus中的ConnectionHolder中的rollbackOnly属性设置成了true。后续提交时判断该属性如果为true就走回滚流程。为什么要设置ConnectionHolder中的属性,是因为该对象与线程绑定了,各个方法之间可以共享该对象
  • 收尾工作,在finally代码块中还有一个cleanupAfterCompletion方法。这个方法做了收尾工作,提交里也有这个方法。后边一起总结

3.2.3、提交处理

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		//判断是否具备提交 条件
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			//使用任务管理器和TransactionStatus执行提交操作  回滚也是这个套路
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}
  • 这里首先看是否具备提交条件,即TransactionStatus非空。目前分析TransactionStatus不能是空的
  • 然后交给事务管理的commit方法执行提交,接下来跟这个方法
public final void commit(TransactionStatus status) throws TransactionException {
		//如果状态是已完成 直接抛出异常 
		//status在提交或者回滚时会被标记为已完成 保证一个status对象只能提交或者回滚一次
		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;
		}
		
		//回滚逻辑回顾 如果不是新事务 设置ConnectionHolder对象的rollbackOnly属性为true
        //defStatus.isGlobalRollbackOnly() 与之前回滚中的逻辑相互呼应 如果rollbackOnly是true 那么这里会进行回滚
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			//这里的第二个参数是true,之前都是flase 区别就是true会抛出一个异常【UnexpectedRollbackException Transaction rolled back because it has been marked as rollback-only】
			processRollback(defStatus, true);
			return;
		}
		//执行提交
		processCommit(defStatus);
	}
  • 首先看status状态是否是已完成,防止重复提交
  • 通过**defStatus.isGlobalRollbackOnly()**方法判断TransactionStatus中的ConnectionHolder中的rollbackOnly属性设置成了true。和回滚中向呼应
  • 最后执行**processCommit()**方法处理提交,继续跟这里
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				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);
		}
	}

大致流程如下

  • 如果有保存点,释放保存点。结合整体来看下保存点的应用。createTransactionIfNecessary方法中创建保存点、回滚处理中回滚到保存点。提交处理中释放保存点
  • 如果是新事务执行提交。这里可以看出只要是新事务提交直接提,回滚直接回
  • 如果是老事务且没有保存点不做任何处理
  • finally中也有善后工作cleanupAfterCompletion方法

3.2.4、提交和回滚的善后工作-挂载事务的修复

还有一些遗留问题。没有处理

  • status对象何时被标记为已完成的?
  • spring管理的数据库连接对象还没还给数据源?
  • 挂起的事务何时被还原?

提交和回滚中都有cleanupAfterCompletion方法,这个方法是做什么的呢?之前事务传播有几种情况回挂载事务,那么挂载的事务是在哪里被修复的呢?答案就在这个方法里。

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
		//这里设置了状态为已完成
		status.setCompleted();
		//这里将线程中绑定的事务相关数据进行清理,其中不包括ConnectionHolder,这个后面单独做
		if (status.isNewSynchronization()) {
			TransactionSynchronizationManager.clear();
		}
		//如果是新事务,需要做一些清理工作

		if (status.isNewTransaction()) {
			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());
		}
	}
  • 这里设置了状态为已完成,和提交与回滚中的状态判断相呼应 保证不重复的提交或者回滚
  • 清理线程中绑定的事务相关数据(其中不包括ConnectionHolder)
  • 如果是新事务,证明提交和回滚操作已经执行完了。需要做一些清理工作
    其一 连接要还给数据库连接池,并且还原其自动提交的能力(spring交出了连接的控制权)
    其二 TransactionSynchronizationManager线程绑定的ConnectionHolder要解绑
  • 如果存在挂载事务将其修复,跟下resume方法
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
			throws TransactionException {

		if (resourcesHolder != null) {
			Object suspendedResources = resourcesHolder.suspendedResources;
			if (suspendedResources != null) {
				//这里将原来的ConnectionHolder重新绑定到TransactionSynchronization中
				doResume(transaction, suspendedResources);
			}
			//这里将之前事务保存到挂载对象的属性还原到TransactionSynchronizationManager中
			List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
			if (suspendedSynchronizations != null) {
				TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
				TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
				TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
				TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
				doResumeSynchronization(suspendedSynchronizations);
			}
		}
	}

到这里收尾工作也完成了

3.2.5、业务代码中是如何获取线程里缓存的数据库连接的

主流程中还遗留一个问题,如果存在事务时业务代码是如何下线程缓存中取连接的?这里涉及到了mybaits的源码。不从头来了直接看下关键类SpringManagedTransaction,该类实现了Transaction。SqlSessionFactoryBean构建SqlSessionFactory时传给SqlSessionFactory。最终SqlSessionFactory构建SqlSession时将SpringManagedTransaction传给SqlSession

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring声明事务是一种在Spring框架中实现事务管理的方,它基于AOP(面向切面编程)的思想,通过将事务管理的逻辑从业务代码中分离出来,使得业务代码不需要关注事务的处理,降低了业务代码的复杂度,并且提高了事务的可控性和可复用性。 Spring声明事务的核心是TransactionInterceptor拦截器,它是一个AOP拦截器,用于拦截带有@Transactional注解的方法,并在方法执行前后自动开启和提交事务。在Spring中,可以通过XML配置或注解的方声明事务,例如: XML配置: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="*" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.service.*.*(..))"/> </aop:config> 注解方: @Configuration @EnableTransactionManagement public class AppConfig { @Bean public DataSource dataSource() { // create and return a DataSource } @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } } @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override @Transactional(propagation = Propagation.REQUIRED) public void saveUser(User user) { userDao.save(user); } } 在上述示例中,我们可以看到声明事务的两种方:XML配置和注解方。其中,<tx:advice>元素用于配置事务通知,<aop:advisor>元素用于配置切入点和通知之间的关联;@EnableTransactionManagement注解用于启用声明事务,@Transactional注解用于标记需要进行事务管理的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值