Spring源码-从源码层面讲解声明式事务的运行流程

TxTest开始执行事务方法:

java 复制代码
public class TxTest {
    public static void main(String[] args) throws SQLException {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code");
        ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.checkout("zhangsan",1);
    }
}

CglibAopProxy执行

bookService.checkout("zhangsan",1);真正执行的时候是调用的代理对象,BookService E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBdbd50224.class

执行checkout跳转到CglibAopProxy的intercept

此时跳转到动态代理执行拦截器逻辑,,有两个拦截器。

ReflectiveMethodInvocation的proceed

ReflectiveMethodInvocation是ProxyMethodInvocation的子类。AOP拦截的执行入口类

java 复制代码
	/**
	 * 递归获取通知,然后执行
	 * @return
	 * @throws Throwable
	 */
	@Override
	@Nullable
	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		// 从索引为-1的拦截器开始调用,并按序递增,如果拦截器链中的拦截器迭代调用完毕,开始调用target的函数,这个函数是通过反射机制完成的
		// 具体实现在AopUtils.invokeJoinpointUsingReflection方法中
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		// 获取下一个要执行的拦截器,沿着定义好的interceptorOrInterceptionAdvice链进行处理
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			// 这里对拦截器进行动态匹配的判断,这里是对pointcut触发进行匹配的地方,如果和定义的pointcut匹配,那么这个advice将会得到执行
			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 {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				// 如果不匹配,那么proceed会被递归调用,知道所有的拦截器都被运行过位置
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			// 普通拦截器,直接调用拦截器,将this作为参数传递以保证当前实例中调用链的执行
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

ExposeInvocationInterceptor拦截器方法调用

return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);执行这个方法到拦截器:

ExposeInvocationInterceptor就是用来传递MethodInvocation的。在后续的任何下调用链环节,只要需要用到当前的MethodInvocation就通过ExposeInvocationInterceptor.currentInvocation()静态方法获得

执行ExposeInvocationInterceptor类的invoke方法中的return mi.proceed();方法又到ReflectiveMethodInvocation的proceed找第二个拦截器准备开始执行TransactionInterceptor的invoke方法


TransactionInterceptor 开始执行

TransactionInterceptor是事务拦截器,实现了方法拦截器MethodInterceptor

第二个拦截器开始执行TransactionInterceptor的方法:invoke,最终跳转到TransactionAspectSupport的invokeWithinTransaction方法

java 复制代码
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		// 获取我们的代理对象的class属性  这里获取到的是bookservice对象
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		/**
		 * 以事务的方式调用目标方法
		 * 在这埋了一个钩子函数 用来回调目标方法的
		 */
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

方法被注解修饰或者
<tx:attributes> <tx:method name="checkout" propagation="REQUIRED" /> <tx:method name="updateStock" propagation="REQUIRES_NEW" /> </tx:attributes>

被这个标签修饰 就是事务方法了

TransactionAspectSupport的invokeWithinTransaction方法源码:

invokeWithinTransaction方法开始执行

java 复制代码
	/**对于基于around-advice的子类的通用委托,委托给其他几个模板
	 */
	@Nullable
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		// 获取我们的事务属性源对象
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 通过事务属性源对象获取到当前方法的事务属性信息
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 获取我们配置的事务管理器对象  获取的是这个标签修饰的对象 <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
		final TransactionManager tm = determineTransactionManager(txAttr);

		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
					throw new TransactionUsageException(
							"Unsupported annotated transaction on suspending function detected: " + method +
							". Use TransactionalOperator.transactional extensions instead.");
				}
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});
			return txSupport.invokeWithinTransaction(
					method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
		}

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		// 获取连接点的唯一标识  类名+方法名  com.study.spring.tx.xml.service.BookService.checkout
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		// 声明式事务处理
		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			// 创建TransactionInfo
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				// 执行被增强方法,调用具体的处理逻辑
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				// 异常回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//清除事务信息,恢复线程私有的老的事务信息
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();

				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			//成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			// 编程式事务处理
			Object result;
			final ThrowableHolder throwableHolder = new ThrowableHolder();

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

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

1.获取我们的事务属性源对象以及通过事务属性源对象获取到当前方法的事务属性信息

invokeWithinTransaction方法内部:getTransactionAttributeSource()方法返回的TransactionAttributeSource

这里用的是接口实现类NameMatchTransactionAttributeSource

java 复制代码
/**
 * 事务属性源,就是事务注解的一些属性,也用来解析事务注解属性
 */
public interface TransactionAttributeSource {
	default boolean isCandidateClass(Class<?> targetClass) {
		return true;
	}
	@Nullable
	TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}

获取我们的事务属性源对象和通过事务属性源对象获取到当前方法的事务属性信息:这里获取到的是在配置文件中配置的方法的隔离级别传播属性等

2.获取我们配置的事务管理器对象

determineTransactionManager

该方法返回值是TransactionManager接口实现类DataSourceTransactionManager

java 复制代码
{@link org.springframework.transaction。PlatformTransactionManager}实现单个JDBC {@link javax.sql.DataSource}。
这个类能够在任何环境中使用任何JDBC驱动程序工作,只要设置使用{@code javax.sql。DataSource}作为{@code Connection}工厂机制。
将来自指定数据源的JDBC连接绑定到当前线程,可能允许每个数据源有一个线程绑定的连接。
<p><b>注意:此事务管理器操作的数据源需要返回独立的连接。
<b> connection可能来自一个池(典型情况),但是DataSource不能返回线程作用域的请求作用域的Connections或类似的东西。
此事务管理器将根据指定的传播行为将Connections与线程绑定的事务本身关联起来。
它假设即使在正在进行的事务期间也可以获得单独的、独立的Connection。
<p>应用程序代码需要通过{@link DataSourceUtilsgetConnection(DataSource)}
而不是标准的Java ee风格的{@link DataSourcegetConnection()}调用来检索JDBC连接。
Spring类,如{@link org.springframework.jdbc.core。JdbcTemplate隐式地使用此策略。
如果不与此事务管理器结合使用,{@link DataSourceUtils}查找策略的行为与本机DataSource查找完全相同;因此,它可以以便携式方式使用。
<p>或者,您可以允许应用程序代码使用标准Java ee风格的查找模式{@link DataSourcegetConnection()},
例如,对于根本不知道Spring的遗留代码。
在这种情况下,为你的目标数据源定义一个{@link TransactionAwareDataSourceProxy},
并将该代理数据源传递给你的dao,它将在访问它时自动参与spring管理的事务。
<p>支持自定义隔离级别,以及作为适当的JDBC语句超时应用的超时。
要支持后者,应用程序代码必须使用{@link org.springframework.jdbc.core。JdbcTemplate},
为每个创建的JDBC语句调用{@link DataSourceUtilsapplyTransactionTimeout},
或者通过{@link TransactionAwareDataSourceProxy}来自动创建超时感知的JDBC连接和语句。
<p>考虑为您的目标数据源定义一个{@link LazyConnectionDataSourceProxy},将此事务管理器和dao都指向它。
这将优化"空"事务的处理,即没有执行任何JDBC语句的事务。
在执行语句之前,LazyConnectionDataSourceProxy不会从目标数据源获取实际的JDBC连接,
并将指定的事务设置惰性地应用于目标连接。
<p>这个事务管理器通过JDBC 3.0 {@link java.sql支持嵌套事务。保存点}机制。
{@link setNestedTransactionAllowed "nestedTransactionAllowed"}标志默认为"true"
,因为嵌套事务将在支持保存点的JDBC驱动程序(如Oracle JDBC驱动程序)上不受限制地工作。
<p>这个事务管理器可以用来代替{@link org.springframework.transaction.jta。JtaTransactionManager}在单一资源的情况下,
因为它不需要支持JTA的容器,通常与本地定义的JDBC数据源(例如Apache Commons DBCP连接池)结合使用。
在本地策略和JTA环境之间切换只是一个配置问题!
<p>从4.3.4开始,这个事务管理器在注册的事务同步(如果同步通常是活动的)上触发flush回调,
假设资源在底层JDBC {@code Connection}上操作。这允许类似于{@code JtaTransactionManager}的设置,
特别是对于惰性注册的ORM资源(例如Hibernate {@code Session})。
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {}

3.createTransactionIfNecessary创建TransactionInfo

java 复制代码
	@SuppressWarnings("serial")
	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;
				}
			};
		}
         //boolean hasSavepoint();  嵌套事务 指定回滚的位置 
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				// 获取TransactionStatus事务状态信息
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		// 根据指定的属性与status准备一个TransactionInfo,
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

事务状态TransactionStatus

设置保存点在嵌套事务中可以指定回滚的位置

java 复制代码
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {

	/**
	 * 是否有保存点
	 */
	boolean hasSavepoint();

	/**
	 * 将会话刷新到数据库中
	 */
	@Override
	void flush();

}

通过设置传播特性设置嵌套事务的回滚
TransactionExecution

java 复制代码
/**
 * Common representation of the current state of a transaction.
 * Serves as base interface for {@link TransactionStatus} as well as
 * {@link ReactiveTransaction}.
 *
 * @author Juergen Hoeller
 * @since 5.2
 */
public interface TransactionExecution {

	/**
	 * 是否为新事务
	 */
	boolean isNewTransaction();

	/**
	 * 设置为只回滚
	 */
	void setRollbackOnly();

	/**
	 * 是否为只回滚
	 */
	boolean isRollbackOnly();

	/**
	 * 当前事务是否已经完成
	 */
	boolean isCompleted();

}

// 获取事务

java 复制代码
	protected Object doGetTransaction() {
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

DataSourceTransactionObject

java 复制代码
	private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {

		private boolean newConnectionHolder;//新链接的包装器

		private boolean mustRestoreAutoCommit;//重新存储的自动提交 对自动提交的设置 

		public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder, boolean newConnectionHolder) {
			super.setConnectionHolder(connectionHolder);
			this.newConnectionHolder = newConnectionHolder;
		}

		public boolean isNewConnectionHolder() {
			return this.newConnectionHolder;
		}

		public void setMustRestoreAutoCommit(boolean mustRestoreAutoCommit) {
			this.mustRestoreAutoCommit = mustRestoreAutoCommit;
		}

		public boolean isMustRestoreAutoCommit() {
			return this.mustRestoreAutoCommit;
		}

		public void setRollbackOnly() {
			getConnectionHolder().setRollbackOnly();
		}

		@Override
		public boolean isRollbackOnly() {
			return getConnectionHolder().isRollbackOnly();
		}

		@Override
		public void flush() {
			if (TransactionSynchronizationManager.isSynchronizationActive()) {
				TransactionSynchronizationUtils.triggerFlush();
			}
		}
	}

JdbcTransactionObjectSupport

java 复制代码
/**
 * Convenient base class for JDBC-aware transaction objects. Can contain a
 * {@link ConnectionHolder} with a JDBC {@code Connection}, and implements the
 * {@link SavepointManager} interface based on that {@code ConnectionHolder}.
 *
 * <p>Allows for programmatic management of JDBC {@link java.sql.Savepoint Savepoints}.
 * Spring's {@link org.springframework.transaction.support.DefaultTransactionStatus}
 * automatically delegates to this, as it autodetects transaction objects which
 * implement the {@link SavepointManager} interface.
 *
 * @author Juergen Hoeller
 * @since 1.1
 * @see DataSourceTransactionManager
 */
public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {

	private static final Log logger = LogFactory.getLog(JdbcTransactionObjectSupport.class);


	@Nullable
	private ConnectionHolder connectionHolder;//连接包装器

	@Nullable
	private Integer previousIsolationLevel;//之前设置的隔离级别

	private boolean readOnly = false;//是否可读

	private boolean savepointAllowed = false;//是否允许设置保存点


	/**
	 * Set the ConnectionHolder for this transaction object.
	 */
	public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder) {
		this.connectionHolder = connectionHolder;
	}

	/**
	 * Return the ConnectionHolder for this transaction object.
	 */
	public ConnectionHolder getConnectionHolder() {
		Assert.state(this.connectionHolder != null, "No ConnectionHolder available");
		return this.connectionHolder;
	}

	/**
	 * Check whether this transaction object has a ConnectionHolder.
	 */
	public boolean hasConnectionHolder() {
		return (this.connectionHolder != null);
	}

	/**
	 * Set the previous isolation level to retain, if any.
	 */
	public void setPreviousIsolationLevel(@Nullable Integer previousIsolationLevel) {
		this.previousIsolationLevel = previousIsolationLevel;
	}

	/**
	 * Return the retained previous isolation level, if any.
	 */
	@Nullable
	public Integer getPreviousIsolationLevel() {
		return this.previousIsolationLevel;
	}

	/**
	 * Set the read-only status of this transaction.
	 * The default is {@code false}.
	 * @since 5.2.1
	 */
	public void setReadOnly(boolean readOnly) {
		this.readOnly = readOnly;
	}

	/**
	 * Return the read-only status of this transaction.
	 * @since 5.2.1
	 */
	public boolean isReadOnly() {
		return this.readOnly;
	}

	/**
	 * Set whether savepoints are allowed within this transaction.
	 * The default is {@code false}.
	 */
	public void setSavepointAllowed(boolean savepointAllowed) {
		this.savepointAllowed = savepointAllowed;
	}

	/**
	 * Return whether savepoints are allowed within this transaction.
	 */
	public boolean isSavepointAllowed() {
		return this.savepointAllowed;
	}

	@Override
	public void flush() {
		// no-op
	}


	//---------------------------------------------------------------------
	// Implementation of SavepointManager
	//---------------------------------------------------------------------

	/**
	 * This implementation creates a JDBC 3.0 Savepoint and returns it.
	 * @see java.sql.Connection#setSavepoint
	 */
	@Override
	public Object createSavepoint() throws TransactionException {
		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
		try {
			if (!conHolder.supportsSavepoints()) {
				throw new NestedTransactionNotSupportedException(
						"Cannot create a nested transaction because savepoints are not supported by your JDBC driver");
			}
			if (conHolder.isRollbackOnly()) {
				throw new CannotCreateTransactionException(
						"Cannot create savepoint for transaction which is already marked as rollback-only");
			}
			return conHolder.createSavepoint();
		}
		catch (SQLException ex) {
			throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);
		}
	}

	/**
	 * This implementation rolls back to the given JDBC 3.0 Savepoint.
	 * @see java.sql.Connection#rollback(java.sql.Savepoint)
	 */
	@Override
	public void rollbackToSavepoint(Object savepoint) throws TransactionException {
		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
		try {
			conHolder.getConnection().rollback((Savepoint) savepoint);
			conHolder.resetRollbackOnly();
		}
		catch (Throwable ex) {
			throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
		}
	}

	/**
	 * This implementation releases the given JDBC 3.0 Savepoint.
	 * @see java.sql.Connection#releaseSavepoint
	 */
	@Override
	public void releaseSavepoint(Object savepoint) throws TransactionException {
		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
		try {
			conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
		}
		catch (Throwable ex) {
			logger.debug("Could not explicitly release JDBC savepoint", ex);
		}
	}

	protected ConnectionHolder getConnectionHolderForSavepoint() throws TransactionException {
		if (!isSavepointAllowed()) {
			throw new NestedTransactionNotSupportedException(
					"Transaction manager does not allow nested transactions");
		}
		if (!hasConnectionHolder()) {
			throw new TransactionUsageException(
					"Cannot create nested transaction when not exposing a JDBC transaction");
		}
		return getConnectionHolder();
	}

}

开始获取事务

只对嵌套事务的保存点生效nested

java 复制代码
	/**
	 * Return whether nested transactions are allowed.
	 */
	public final boolean isNestedTransactionAllowed() {
		return this.nestedTransactionAllowed;
	}

nestedTransactionAllowed哪里赋值的?

DataSourceTransactionManager实例化的时候:

ConnectionHolder:

java 复制代码
包装JDBC连接的资源持有者。DataSourceTransactionManager将该类的实例绑定到线程,用于特定的javax.sql.DataSource。继承基类对嵌套JDBC事务和引用计数功能的仅回滚支持。
public class ConnectionHolder extends ResourceHolderSupport 

TransactionSynchronizationManager:

java 复制代码
管理每个线程的资源和事务同步的中心委托。由资源管理代码使用,而不是由典型的应用程序代码使用。支持每个键一个资源,不覆盖,即在为同一键设置新资源之前需要删除一个资源。如果同步是活动的,则支持事务同步列表。资源管理代码应该通过getResource检查线程绑定的资源,例如JDBC连接或Hibernate会话。这样的代码通常不应该将资源绑定到线程,因为这是事务管理器的责任。另一个选项是,如果事务同步是活动的,则在第一次使用时惰性绑定,用于执行跨越任意数量资源的事务。事务同步必须由事务管理器通过initSynchronization()和clearSynchronization()激活和取消激活。AbstractPlatformTransactionManager自动支持此功能,因此所有标准的Spring事务管理器都支持此功能,例如org.springframework.transaction.jta. jtattransactionmanager和org.springframework.jdbc.datasource.DataSourceTransactionManager。资源管理代码应该只在这个管理器处于活动状态时注册同步,这可以通过isSynchronizationActive来检查;它应该立即执行资源清理。如果事务同步不是活动的,则要么没有当前事务,要么事务管理器不支持事务同步。例如,同步用于在JTA事务中始终返回相同的资源,例如,对于任何给定的数据源或SessionFactory,分别使用JDBC连接或Hibernate会话。
public abstract class TransactionSynchronizationManager

TransactionSynchronizationManager.getResource(obtainDataSource()):

javascript 复制代码
	/**
	检索绑定到当前线程的给定键的资源。参数:key -要检查的键(通常是资源工厂)返回:绑定到当前线程的值(通常是活动的资源对象),如果没有则为空参见:ResourceTransactionManager.getResourceFactory()
	 */
	@Nullable
	public static Object getResource(Object key) {
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		Object value = doGetResource(actualKey);
		if (value != null && logger.isTraceEnabled()) {
			logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
					Thread.currentThread().getName() + "]");
		}
		return value;
	}

doGetResource:

获取事务从当前线程

java 复制代码
private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

此时还没建立任何的连接:

如果外层有事务在这里就会获取到

开启事务:



** doBegin(transaction, definition);**

java 复制代码
	@Override
	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();//先获取数据源 然后去DruidDataSource获取连接
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();
            //设置可读属性和隔离级别
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			txObject.setReadOnly(definition.isReadOnly());

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);

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

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

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

Connection newCon = obtainDataSource().getConnection();//先获取数据源 然后去DruidDataSource获取连接

prepareTransactionalConnection设置只读事务

java 复制代码
	/**
	 在事务开始后立即准备事务连接。如果"enforceReadOnly"标志被设置为true并且事务定义为只读事务,则默认实现执行"SET TRANSACTION READ ONLY"语句。"SET TRANSACTION READ ONLY"可以被Oracle, MySQL和Postgres理解,也可以在其他数据库中使用。如果您想调整此处理,请相应地覆盖此方法。
	 */
	protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)
			throws SQLException {

		if (isEnforceReadOnly() && definition.isReadOnly()) {
			try (Statement stmt = con.createStatement()) {
				stmt.executeUpdate("SET TRANSACTION READ ONLY");
			}
		}
	}
java 复制代码
	/**
	 * Start a new transaction.
	 */
	private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		doBegin(transaction, definition);//上面已经讲完
		prepareSynchronization(status, definition);
		return status;
	}
java 复制代码
	/**
	 * Initialize transaction synchronization as appropriate.根据需要初始化事务同步。
	 */
	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();
		}
	}
java 复制代码
	/**
	 必要时根据给定的TransactionAttribute创建事务。
	 允许调用者通过TransactionAttributeSource执行自定义的TransactionAttribute查找。
	 Params: txAttr---TransactionAttribute(可能为null) joinpointIdentification---完全限定的方法名(用于监视和记录目的)
	 返回:一个TransactionInfo对象,无论是否创建了事务。
	 TransactionInfo上的hastrtransaction()方法可用于判断是否创建了事务。参见:getTransactionAttributeSource()
	 */
	@SuppressWarnings("serial")
	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);
	}

prepareTransactionInfo

java 复制代码
	/**
	为给定的属性和状态对象准备一个TransactionInfo。
	Params: txAttr---TransactionAttribute(可能为null) 
	joinpointIdentification---完全限定的方法名称(用于监视和记录目的)状态---当前事务的    
	TransactionStatus
	返回:准备好的TransactionInfo对象
	 */
	protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, String joinpointIdentification,
			@Nullable TransactionStatus status) {

		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			// We need a transaction for this method...
			if (logger.isTraceEnabled()) {
				logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// The transaction manager will flag an error if an incompatible tx already exists.如果不兼容的tx已经存在,事务管理器将标记一个错误。
			txInfo.newTransactionStatus(status);
		}
		else {
			// The TransactionInfo.hasTransaction() method will return false. We created it only
			// to preserve the integrity of the ThreadLocal stack maintained in this class.
			hastrtransaction()方法将返回false。我们创建它只是为了保持在这个类中维护的ThreadLocal堆栈的完整性。
			if (logger.isTraceEnabled()) {
				logger.trace("No need to create transaction for [" + joinpointIdentification +
						"]: This method is not transactional.");
			}
		}
        //我们总是将TransactionInfo绑定到线程,即使我们没有在这里创建新事务。这保证了TransactionInfo堆栈将被正确管理,即使这个方面没有创建任何事务。
		// We always bind the TransactionInfo to the thread, even if we didn't create
		// a new transaction here. This guarantees that the TransactionInfo stack
		// will be managed correctly even if no transaction was created by this aspect.
		txInfo.bindToThread();
		return txInfo;
	}

bindToThread

java 复制代码
	private void bindToThread() {
			// Expose current TransactionStatus, preserving any existing TransactionStatus
			// for restoration after this transaction is complete.公开当前的TransactionStatus,保留任何现有的TransactionStatus,以便在此事务完成后恢复。
			this.oldTransactionInfo = transactionInfoHolder.get();
			transactionInfoHolder.set(this);
		}

TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);方法执行结束之后表示跟事务相关的所有信息都已经准备好了,接下来开始执行增强方法:

执行增强方法路径截图如下:最终指向service的方法:





bookDao也是一个代理对象,所以还是会执行到CglibAopProxy的intercept方法,最终还是会TransactionInterceptor的invokeWithinTransaction

TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);执行到这个方法里的时候不会再创建新的事务因为从上一次创建的对象放到缓存里了直接取,并且propagation="REQUIRED"

create方法一直到doGetResource:

java 复制代码
private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");




开始执行handleExistingTransaction:

java 复制代码
为现有事务创建一个TransactionStatus。
private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {//	int PROPAGATION_NEVER = 5;不支持当前事务;如果存在当前事务,则抛出异常。类似于同名的EJB事务属性。注意,事务同步在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);
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
				return startTransaction(definition, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}

		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.
				//通过TransactionStatus实现的SavepointManager API,在现有的spring管理的事务中创建保存点。通常使用JDBC 3.0保存点。从不激活Spring同步。
				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.
				//通过嵌套的begin和commitrollback调用进行嵌套事务。通常只针对JTA:在存在预先存在的JTA事务的情况下,这里可能会激活Spring同步。
				return startTransaction(definition, transaction, debugEnabled, null);
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}
		if (isValidateExistingTransaction()) {
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
					Constants isoConstants = DefaultTransactionDefinition.constants;
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] specifies isolation level which is incompatible with existing transaction: " +
							(currentIsolationLevel != null ?
									isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
									"(unknown)"));
				}
			}
			if (!definition.isReadOnly()) {
				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] is not marked as read-only but existing transaction is");
				}
			}
		}
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

从这里开始执行dao中的sql,代理方法跳转到目标对象的方法:

sql执行之后如果有异常执行completeTransactionAfterThrowing,否则直接执行cleanupTransactionInfo

cleanupTransactionInfo(txInfo);

java 复制代码
	/**
重置TransactionInfo ThreadLocal。在所有情况下都调用这个:异常或正常返回!参数:txInfo -关于当前事务的信息(可能为空)
	 */
	protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
		if (txInfo != null) {
			txInfo.restoreThreadLocalStatus();
		}
	}

restoreThreadLocalStatus

java 复制代码
	private void restoreThreadLocalStatus() {
			// Use stack to restore old transaction TransactionInfo.
			// Will be null if none was set.使用堆栈恢复旧事务TransactionInfo。如果未设置,则为空。
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

commitTransactionAfterReturning(txInfo);

java 复制代码
   //在成功完成调用后执行,但不是在处理异常之后执行。如果我们没有创建一个事务,什么也不做。参数:txInfo -关于当前事务的信息
	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());
		}
	}

txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());

java 复制代码
	/**
	 commit的这个实现处理参与现有事务和编程式回滚请求。委托给isRollbackOnly, doCommit和rollback。
	 参见:TransactionStatus.isRollbackOnly(), doCommit, rollback
	 */
	@Override
	public final void commit(TransactionStatus status) throws TransactionException {
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}

		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			processRollback(defStatus, true);
			return;
		}
        前面回滚的不执行 就到这里 进行提交
		processCommit(defStatus);
	}
processCommit(defStatus);
java 复制代码
处理实际提交。已经检查并应用了仅回滚标志。参数:状态---表示事务的对象。在提交失败的情况下抛出:TransactionException
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				triggerBeforeCommit(status);//提交之前触发的操作
				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);
		}
	}

cleanupAfterCompletion(status);

java 复制代码
完成后清理,必要时清除同步,并调用doCleanupAfterCompletion。参数:状态-对象表示事务参见:doCleanupAfterCompletion
	private void cleanupAfterCompletion(DefaultTransactionStatus status) {
		status.setCompleted();
		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());
		}
	}

commitTransactionAfterReturning(txInfo);执行结束之后

事务的提交

service的checkout方法执行结束开始提交事务

相关推荐
代码之光_19809 分钟前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi15 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
StayInLove34 分钟前
G1垃圾回收器日志详解
java·开发语言
对许38 分钟前
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“
java·log4j
鹿屿二向箔39 分钟前
基于SSM(Spring + Spring MVC + MyBatis)框架的咖啡馆管理系统
spring·mvc·mybatis
无尽的大道42 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
小鑫记得努力1 小时前
Java类和对象(下篇)
java
binishuaio1 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE1 小时前
【Java SE】StringBuffer
java·开发语言
老友@1 小时前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose