IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring声明式事务执行流程源码分析 -> 正文阅读

[Java知识库]Spring声明式事务执行流程源码分析

1.执行入口

StudentService studentService = (StudentService) defaultIistableBeanFactory.getBean("studentServiceProxy");
studentService.saveStudent(student)

如果一个方法开启了事务,最终在getBean的时候,获取到的一定是代理对象。当执行saveStudent方法时进入JdkDynamicAopProxy类的invoke方法。

在这里插入图片描述
对于动态代理来说当他调用任何一个方法的时候,这个流程都会进入与之相关的InvocationHandler里的invoke方法。

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	// 获取目标对象源(要代理的目标对象源)
	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			return equals(args[0]);
		}
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		Object retVal;

		if (this.advised.exposeProxy) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// 要代理的真正目标对象
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 获得针对这个方法的所有拦截器链
		// 这里我们获取到事务拦截器TransactionInterceptor
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// 如果连接器链为空 直接调用目标方法
		if (chain.isEmpty()) {
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// 创建方法调用 将拦截器封装在 ReflectiveMethodInvocation
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// 执行拦截器链
			retVal = invocation.proceed();
		}

		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

上面的函数中最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation 类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐 调用。

@Override
@Nullable
public Object proceed() throws Throwable {
	// 执行完所有增强后执行切点方法
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	// 获取下一个要执行的拦截器
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
	
			return proceed();
		}
	}
	else {
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

TransactionInterceptor 支撑着整个事务功能的架构,接下来我们看下事务拦截器的处理逻辑。

2.事务三大接口

我们先了解下spring中管理事务的三个非常重要的接口

PlatformTransactionManager 事务管理器
TransactionDefinition 事务的一些基础信息,如超时时间、隔离级别、传播属性等
TransactionStatus 事务的一些状态信息,如是否一个新的事务、是否已被标记为回滚

事务管理器PlatformTransactionManager

public interface PlatformTransactionManager extends TransactionManager {
	// //根据事务定义TransactionDefinition,获取事务
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
    // 提交事务
	void commit(TransactionStatus status) throws TransactionException;
    // 回滚事务
	void rollback(TransactionStatus status) throws TransactionException;
}

事务定义接口TransactionDefinition

// 事务的定义包括: 事务的隔离级别,事务的传播属性,超时时间设置,
// 是否只读事务的隔离级别是数据库本身的事务功能,事务的播属性则是spring为我们提供的功能
// 该接口的实现DefaultTransactionDefinition,默认的事务定义
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
	// 事务的传播属性默认为PROPAGATION_REQUIRED,即当前没有事务的时候,创建一个,如果有则使用当前事务
   private int propagationBehavior = PROPAGATION_REQUIRED;
   // 事务的隔离级别采用底层数据库默认的隔离级别
   private int isolationLevel = ISOLATION_DEFAULT;
   // 超时时间采用底层数据库默认的超时时间
   private int timeout = TIMEOUT_DEFAULT;
   // 是否只读为false
   private boolean readOnly = false;
   ...
} 

事务状态接口TransactionStatus
TransactionStatus本身更多存储的是事务的一些状态信息 是否是一个新的事物 是否有保存点 是否已被标记为回滚

public DefaultTransactionStatus(
		@Nullable Object transaction, boolean newTransaction, boolean newSynchronization,
		boolean readOnly, boolean debug, @Nullable Object suspendedResources) {
	// 事务实例
	this.transaction = transaction;
	/***当前事务是否为新事物*/
	this.newTransaction = newTransaction;
	this.newSynchronization = newSynchronization;
	this.readOnly = readOnly;
	this.debug = debug;
	// 挂起的事务信息对象
	this.suspendedResources = suspendedResources;
}

3.TransactionInterceptor 事务拦截器

TransactionInterceptor 支撑着整个事务功能的架构,逻辑还是相对复杂的,那么现在我们切入 正题来分析此拦截器是如何实现事务特性的。TransactionInterceptor类继承自 MethodInterceptor, 所 以调用该类是从其 invoke方法开始的,首先预览下这个方法:

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {

	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

核心行法 invokeWithinTransaction 我们只看声明式事务的逻辑

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

	// 获取TransactionAttributeSource,这个对象在初始化TransactionInterceptor时就初始化了
	TransactionAttributeSource tas = getTransactionAttributeSource();
	// 从tas中获取txAttr事务属性,如果缓存有就直接取缓存,如果缓存没有就直接解析
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 确定和返回事务管理器 这里如果配置没有指定transaction-manager并且也没有默认id名为transactionManager的bean
	final TransactionManager tm = determineTransactionManager(txAttr);
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

	// 申明式事务的处理
	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// 创建事务信息(开启一个事务)
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

		Object retVal;
		try {
			// 调用目标方法 环绕通知
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception 异常处理
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			cleanupTransactionInfo(txInfo); // 清空事务
		}
		// 提交事务
		commitTransactionAfterReturning(txInfo);
		return retVal;
	} else {
		// 编程式事务...
	}
}

3.1 创建事务

我们先分析事务创建的过程。

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

	// If no name specified, apply method identification as transaction name.
	// 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute 封装txAttr
	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);
}

1.获取事务

Spring 中使用 getTransaction来处理事务的准备工作,包括事务获取以及信息的构建。

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
  //得到一个事务对象,我们这里用的是DatasourceTransactionManager, 所以这个事务对象就是DataSourceTransactionManager.DataSourceTransactionObject
  Object transaction = doGetTransaction();
 
  boolean debugEnabled = logger.isDebugEnabled();
 
  if (definition == null) {
    definition = new DefaultTransactionDefinition();
  }
 
  // 2.判断当前线程是否存在事务,判读依据为当前线程记录的连接不为空且连接中(connectionHolder)中的 transactionActive 属性不为空
  if (isExistingTransaction(transaction)) {
    // 当前线程已经存在事务
    return handleExistingTransaction(definition, transaction, debugEnabled);
  }
 
  // 事务超时设置验证 默认-1 小于 -1 抛异常
  if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
    throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
  }
 
  // 3. 如果当前没有事务,不同的事务传播方式不同处理方式
  // 3.1 事务传播方式为mandatory(强制必须有事务),则抛出异常
  if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
    throw new IllegalTransactionStateException(
        "No existing transaction found for transaction marked with propagation 'mandatory'");
  }
  // 3.2 事务传播方式为required或required_new或nested(嵌套),创建一个新的事务状态
  else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
      definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
      definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
     // 挂起事务
    SuspendedResourcesHolder suspendedResources = suspend(null);
    if (debugEnabled) {
      logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
    }
    try {
      boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
      // 创建新的事务状态对象
      DefaultTransactionStatus status = newTransactionStatus(
          definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
      // 开启事务
      doBegin(transaction, definition);
      // 同步事务状态
      prepareSynchronization(status, definition);
      return status;
    }
    catch (RuntimeException | Error ex) {
      resume(null, suspendedResources);
      throw ex;
    }
  }
  // 3.3 其他事务传播方式,返回一个事务对象为null的事务状态对象
  else {
    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);
  }
}

当然,在Spring中每个复杂的功能实现,并不是一次完成的,而是会通过入口函数进行一 个框架的搭建,初步构建完整的逻辑,而将实现细节分摊给不同的函数。那么,让我们看看事 务的准备工作都包括哪些。

(1)获取事务 创建对应的事务实例,这里使用的是DataSource TransactionManager 中的doGet Transaction 方法,创建基于JDBC 的事务实例。如果当前线程中存在关于 dataSource的连接,那么直接使 用。这里有一个对保存点的设置,是否开启允许保存点取决于是否设置了允许嵌入式事务。

@Override
protected Object doGetTransaction() {
	// 创建事务对象
	DataSourceTransactionObject txObject = new DataSourceTransactionObject();
	// 设置允许嵌套事务的保存点
	txObject.setSavepointAllowed(isNestedTransactionAllowed());
	// 从当前线程中获取已经记录好的数据库连接信息,如果有的话
	ConnectionHolder conHolder =
			(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
	// 将连接信息设置到事务对象中,false表示这个连接不是新创建的。
	txObject.setConnectionHolder(conHolder, false);
	return txObject;
}

(2)如果当先线程存在事务,则转向嵌套事务的处理。
(3)事务超时设置验证。
(4)事务propagationBehavior属性的设置验证。
(5构建DefaultTransactionStatus。
(6)完善 transaction, 包括设置ConnectionHolder、隔离级别、timeout, 如果是新连接, 则绑定到当前线程.
对于一些隔离级别、timeout等功能的设置并不是由 Spring 来完成的,而是委托给底层的 数据库连接去做的,而对于数据库连接的设置就是在 doBegin 函数中处理的。
(7)将事务信息记录在当前线程中prepareSynchronization。

当前有事务
Spring中支持多种事务的传播规则,比如 PROPAGATION NESTED、PROPAGATION REQUIRES NEW等,这些都是在已经存在事务的基础上进行进 步的处理,那么,对于已经存在的事务,准备操作是如何进行的呢?
如果当前已经有事务存在,由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'");
  }
 
  // 传播方式为not_supported(不支持),则挂起当前事务,以无事务方式运行
  if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
    if (debugEnabled) {
      logger.debug("Suspending current transaction");
    }
    //挂起当前事务 
    //suspendedResources 所谓挂起事物,就是把目前线程中所有储存的信息,都保存起来,返回一个suspendedResources对象 
    //并且把当前线程中的事物相关信息都清空,方便下一个事物newSynchronization和prepareTransactionStatus()中判断 
    //来更新到线程中
    Object suspendedResources = suspend(transaction);
    boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
    //创建一个新的事务状态,非事务状态运行 
    //参数2事务对象为null, 参数3是否新事务为false, 参数6是挂起的事务信息对象
    return prepareTransactionStatus(
        definition, null, false, newSynchronization, debugEnabled, suspendedResources);
  }
 
  // 传播方式为required_new,挂起原有事务,并开启新的事务
  if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    if (debugEnabled) {
      logger.debug("Suspending current transaction, creating new transaction with name [" +
          definition.getName() + "]");
    }
    // 挂起当前事务
    SuspendedResourcesHolder suspendedResources = suspend(transaction);
    try {
      boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
      // 创建一个新的事务状态
      DefaultTransactionStatus status = newTransactionStatus(
          definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
       // 开启事务
      doBegin(transaction, definition);
      // 事务同步到本地线程
      prepareSynchronization(status, definition);
      return status;
    }
    catch (RuntimeException | Error beginEx) {
      resumeAfterBeginException(transaction, suspendedResources, beginEx);
      throw beginEx;
    }
  }
 
  // 传播方式为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()) {
      DefaultTransactionStatus status =
          prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
       // 设置保存点
      status.createAndHoldSavepoint();
      return status;
    }
    // 只适用于JTA事务:通过嵌套的begin和commit/rollback创建嵌套事务
    else {
      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.
  // 传播方式为supports或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);
}

3.2 事务的挂起

对于挂起操作的主要目的是记录原有事务的状态,以便于后续操作对事务的恢复:

Spring并不是真的对数据库连接做了什么挂起操作,而是在逻辑上由事务同步管理器做了事务信息和状态的重置,并将原事务信息和状态返回,并记录在新的事务状态对象中,新事务执行完成再打开挂起的事务。

@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
	if (TransactionSynchronizationManager.isSynchronizationActive()) {
		//执行注册方法,并全部取出,把当前线程事物设置为不同步状态,说明这个事物已经被挂起了
		List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
		try {
			Object suspendedResources = null;
			if (transaction != null) {
				// 在DataSource的状态下,是取出连接的持有者对象
				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) {
			doResumeSynchronization(suspendedSynchronizations);
			throw ex;
		}
	}
	else if (transaction != null) {
		Object suspendedResources = doSuspend(transaction);
		return new SuspendedResourcesHolder(suspendedResources);
	}
	else {
		return null;
	}
}

3.3 开启事务

如何创建一个新的事务状态

// 1. 新建事务状态,返回DefaultTransactionStatus对象
DefaultTransactionStatus status = newTransactionStatus(
    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 2. 开启事务
doBegin(transaction, definition);
// 3. 将事务同步到当前线程
prepareSynchronization(status, definition);
return status;

第一步,新建事务状态,就是构建一个DefaultTransactionStatus对象

protected DefaultTransactionStatus newTransactionStatus(
    TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
    boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
 
  boolean actualNewSynchronization = newSynchronization &&
      !TransactionSynchronizationManager.isSynchronizationActive();
  return new DefaultTransactionStatus(
      transaction, newTransaction, actualNewSynchronization,
      definition.isReadOnly(), debug, suspendedResources);
}
public DefaultTransactionStatus(
		@Nullable Object transaction, boolean newTransaction, boolean newSynchronization,
		boolean readOnly, boolean debug, @Nullable Object suspendedResources) {

	this.transaction = transaction;
	this.newTransaction = newTransaction;
	this.newSynchronization = newSynchronization;
	this.readOnly = readOnly;
	this.debug = debug;
	this.suspendedResources = suspendedResources;
}

第二步,对于一些隔离级别、timeout等功能的设置并不是由 Spring 来完成的,而是委托给底层的 数据库连接去做的,而对于数据库连接的设置就是在 doBegin 函数中处理的。

// 构造transaction,包括设置ConnectionHolder、隔离级别、timeout 如果是新连接,绑定到当前线程
protected void doBegin(Object transaction, TransactionDefinition definition) {
  DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
  Connection con = null;
 
  try {
  	// 新的事务,没有连就获取一个连接
    if (!txObject.hasConnectionHolder() ||
        txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
      Connection newCon = obtainDataSource().getConnection();
      if (logger.isDebugEnabled()) {
        logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
      }
      txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
    }
 
	// 设置数据库连接与事务同步
    txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
    con = txObject.getConnectionHolder().getConnection();
 
	// 设置事务隔离级别
    Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
    txObject.setPreviousIsolationLevel(previousIsolationLevel);
    // 非常重要的一点,JDBC通过设置自动提交为false, 事务提交交由spring管理
    if (con.getAutoCommit()) {
      txObject.setMustRestoreAutoCommit(true);
      if (logger.isDebugEnabled()) {
        logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
      }
      con.setAutoCommit(false);
    }
 
	// 如果设置事务只读属性,执行Statement设置只读
    prepareTransactionalConnection(con, definition);
    // 激活事务状态
    txObject.getConnectionHolder().setTransactionActive(true);
 
	// 设置超时时间
    int timeout = determineTimeout(definition);
    if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
      txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
    }
    
     //把新的连接绑定到当前线程(当前线程的Threadloca1中有一个map)
    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);
  }
}

可以说事务是从这个函数开始的,因为在这个函数中已经开始尝试了对数据库连接的获 取,当然,在获取数据库连接的同时,一些必要的设置也是需要同步设置的。

第三步,将事务同步到当前线程

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
	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());
		TransactionSynchronizationManager.initSynchronization();
	}
}

3.4 事务回滚

当出现错误时,Spring是怎么对数据恢复的呢?

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);
		}
		// 这里判断是否回滚默认的依据是抛出的异常是否是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;
			}
		}
	}
}

回滚条件
在对目标方法的执行过程中,一旦出现Throwable 就会被引导至此方法处理,但是并不代表所有的 Throwable 都会被回滚处理,比如我们最常用的 Exception, 默认是不会被处理的。 默认情况下,即使出现异常,数据也会被正常提交,而这个关键的地方就是在txInfo.transactionAttribute.rollbackOn(ex)这个函数。

public boolean rollbackOn(Throwable ex) {
    // 默认情况下对RuntimeException 和Error类型的迸行回滚
   return ex instanceof RuntimeException || ex instanceof Error;
}

默认情况下 Spring中的事务异常处理机制只对RuntimeException 和 Error两种情况感兴趣,当然你可以通过扩展来改变,不过,我们最常用的还是使用事务提供的属性设置, 利用注解方式的使用,例如:

@Transactional(rollbackFor = Exception.class)

回滚处理
一旦符合回滚条件,那么Spring 就会将程序引导至回滚处理函数中。

@Override
public final void rollback(TransactionStatus status) throws TransactionException {
	// 如果事务状态已完成,则回滚抛出异常
	if (status.isCompleted()) {
		throw new IllegalTransactionStateException(
				"Transaction is already completed - do not call commit or rollback more than once per transaction");
	}

	DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
	processRollback(defStatus, false);
}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
	try {
		boolean unexpectedRollback = unexpected;

		try {
			// 激活所有Transactionsynchronization 中对应的方法
			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 {
				if (status.hasTransaction()) {
					if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
						if (status.isDebug()) {
							logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
						}
						//如果当前事务不是独立的事务,则只能等待事务链执行完成之后再回滚 
						//在这里将其标记为仅回滚
						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");
				}
				if (!isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = false;
				}
			}
		}
		catch (RuntimeException | Error ex) {
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw ex;
		}
		//激活所有 TransactionSynchronization 中对应的方法
		triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

		if (unexpectedRollback) {
			throw new UnexpectedRollbackException(
					"Transaction rolled back because it has been marked as rollback-only");
		}
	}
	finally {
	     // 清空记录的资源并将挂起的资源恢复
		cleanupAfterCompletion(status);
	}
}

回滚保存点和回滚事务都由JDBC的API来完成。

3.5 自定义触发器调用

我们可以使用自定义触发器,再事务处理过程中做一些额外的扩展,而对于 触发器的注册,常见是在回调过程中通过 TransactionSynchronizationManager 类中的静态方法 直接注册:

public static void registerSynchronization(TransactionSynchronization synchronization)
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
    public TransactionSynchronizationAdapter() {
    }

    public int getOrder() {
        return 2147483647;
    }

    public void suspend() {
    }

    public void resume() {
    }

    public void flush() {
    }

	// 在事务提交之前调用(在“完成之前”)
    public void beforeCommit(boolean readOnly) {
    }

	/*
	在事务提交/回滚之前调用。可以在事务完成之前执行资源清理。
	此方法将在beforeCommit之后调用,即使beforeCommit引发异常也是如此。此回调允许在事务完成之前关		闭资源,以获得任何结果。
	*/
    public void beforeCompletion() {
    }

	/*
	 *在事务提交后调用。可以在主事务成功提交后立即执行进一步的操作。
	 *例如,可以提交在成功提交主事务后应该进行的进一步操作,如确认消息或电子邮件。
	 */
    public void afterCommit() {
    }

    // 在事务提交/回滚后调用。可以在事务完成后执行资源清理。
    public void afterCompletion(int status) {
    }
}

代码举例 我们可以在事务提交后做一些额外的处理

@Override
@Transactional(rollbackFor = Exception.class)
public int delete(Long id) {

	  // 数据库操作逻辑

	  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
	  	// 在事务提交后调用。可以在主事务成功提交后立即执行进一步的操作。
	    @Override
	    public void afterCommit() {
	      // TODO
	    }
	});

}

3.6 提交事务

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
	// 判断是否存在事务
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		if (logger.isTraceEnabled()) {
			logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
		}
		txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
	}
}

在真正的数据提交之前,还需要做个判断。在我们分析事务异 常处理规则的时候,当某个事务既没有保存点又不是新事物,Spring 对它的处理方式只是设置 一个回滚标识。这个回滚标识在这里就会派上用场了,主要的应用场景如下。

某个事务是另一个事务的嵌入事务,但是,这些事务又不在Spring 的管理范围内,或者无 法设置保存点,那么 Spring 会通过设置回滚标识的方式来禁止提交。首先当某个嵌入事务发生 回滚的时候会设置回滚标识,而等到外部事务提交时,一旦判断出当前事务流被设置了回滚标 识,则由外部事务来统一进行整体事务的回滚。

所以说commit方法并不是一定提交事务,也可能回滚。

@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;
	}
	// 设置全局回滚标识为true,则执行回滚
	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);
}

而当事务执行一切都正常的时候,便可以真正地进入提交流程了。

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
	try {
		boolean beforeCompletionInvoked = false;

		try {
			boolean unexpectedRollback = false;
			prepareForCommit(status); //提交前的准备,其实do no thing
			triggerBeforeCommit(status); // 触发所有的 BeforeCommit
			triggerBeforeCompletion(status); // 触发所有的 BeforeCompletion
			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);
	}
}

在提交过程中也并不是直接提交的,而是考虑了诸多的方面,符合提交的条件如下。

  • 当事务状态中有保存点信息的话便不会去提交事务。
  • 当事务非新事务的时候也不会去执行提交事务操作。

此条件主要考虑内嵌事务的情况,对于内嵌事务,在Spring 中正常的处理方式是将内嵌事 务开始之前设置保存点,一旦内嵌事务出现异常便根据保存点信息进行回滚,但是如果没有出 现异常,内嵌事务并不会单独提交,而是根据事务流由最外层事务负责提交,所以如果当前存 在保存点信息便不是最外层事务,不做保存操作,对于是否是新事务的判断也是基于此考虑。

Spring会将 事务提交的操作引导至底层数据库连接的API,进行事务提交。

protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        this.logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    }

    try {
    	// 提交事务
        con.commit();
    } catch (SQLException var5) {
        throw new TransactionSystemException("Could not commit JDBC transaction", var5);
    }
}

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

参考资料:
Spring源码深度解析https://book.douban.com/subject/25866350/

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:04:04  更:2022-04-06 16:08:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:05:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码