spring5 源码深度解析----- 事务增强器(100%理解事务)
上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的,也讲解了Spring是如何将有配置事务的类配置上事务的,实际上也就是用了AOP那一套,也讲解了Advisor,pointcut验证流程,至此,事务的初始化工作都已经完成了,在之后的调用过程,如果代理类的方法被调用,都会调用BeanFactoryTransactionAttributeSourceAdvisor这个Advisor的增强方法,也就是我们还未提到的那个Advisor里面的advise,还记得吗,在自定义标签的时候我们将TransactionInterceptor这个Advice作为bean注册进IOC容器,并且将其注入进Advisor中,这个Advice在代理类的invoke方法中会被封装到拦截器链中,最终事务的功能都在advise中体现,所以我们先来关注一下TransactionInterceptor这个类吧。
TransactionInterceptor类继承自MethodInterceptor,所以调用该类是从其invoke方法开始的,首先预览下这个方法:
@Override
@Nullable
public Object invoke(final 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<?> 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 { // If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
// 获取对应事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取beanFactory中的transactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 构造方法唯一标识(类.方法,如:service.UserServiceImpl.save)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 声明式事务处理
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 创建TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行原方法
// 继续调用方法拦截器链,这里一般将会调用目标类的方法,如:AccountServiceImpl.save方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
// 手动向上抛出异常,则下面的提交事务不会执行
// 如果子事务出异常,则外层事务代码需catch住子事务代码,不然外层事务也会回滚
throw ex;
}
finally {
// 消除信息
cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
try {
// 编程式事务处理
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}); // Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
创建事务Info对象
我们先分析事务创建的过程。
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) {
// 获取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);
}
对于createTransactionlfNecessary函数主要做了这样几件事情。
(1)使用 DelegatingTransactionAttribute 封装传入的 TransactionAttribute 实例。
对于传入的TransactionAttribute类型的参数txAttr,当前的实际类型是RuleBasedTransactionAttribute,是由获取事务属性时生成,主要用于数据承载,而这里之所以使用DelegatingTransactionAttribute进行封装,当然是提供了更多的功能。
(2)获取事务。
事务处理当然是以事务为核心,那么获取事务就是最重要的事情。
(3)构建事务信息。
根据之前几个步骤获取的信息构建Transactionlnfo并返回。
获取事务
其中核心是在getTransaction方法中:
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 获取一个transaction
Object transaction = doGetTransaction(); boolean debugEnabled = logger.isDebugEnabled(); if (definition == null) {
definition = new DefaultTransactionDefinition();
}
// 如果在这之前已经存在事务了,就进入存在事务的方法中
if (isExistingTransaction(transaction)) {
return handleExistingTransaction(definition, transaction, debugEnabled);
} // 事务超时设置验证
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
} // 走到这里说明此时没有存在事务,如果传播特性是MANDATORY时抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 如果此时不存在事务,当传播特性是REQUIRED或NEW或NESTED都会进入if语句块
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED都需要新建事务
// 因为此时不存在事务,将null挂起
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// new一个status,存放刚刚创建的transaction,然后将其标记为新事务!
// 这里transaction后面一个参数决定是否是新事务!
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;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
// 其他的传播特性一律返回一个空事务,transaction = null
//当前不存在事务,且传播机制=PROPAGATION_SUPPORTS/PROPAGATION_NOT_SUPPORTED/PROPAGATION_NEVER,这三种情况,创建“空”事务
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
先来看看transaction是如何被创建出来的:
@Override
protected Object doGetTransaction() {
// 这里DataSourceTransactionObject是事务管理器的一个内部类
// DataSourceTransactionObject就是一个transaction,这里new了一个出来
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 解绑与绑定的作用在此时体现,如果当前线程有绑定的话,将会取出holder
// 第一次conHolder肯定是null
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
// 此时的holder被标记成一个旧holder
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
创建transaction过程很简单,接着就会判断当前是否存在事务:
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
} public boolean hasConnectionHolder() {
return (this.connectionHolder != null);
}
这里判断是否存在事务的依据主要是获取holder中的transactionActive变量是否为true,如果是第一次进入事务,holder直接为null判断不存在了,如果是第二次进入事务transactionActive变量是为true的(后面会提到是在哪里把它变成true的),由此来判断当前是否已经存在事务了。
至此,源码分成了2条处理线
1.当前已存在事务:isExistingTransaction()判断是否存在事务,存在事务handleExistingTransaction()根据不同传播机制不同处理
2.当前不存在事务: 不同传播机制不同处理
当前不存在事务
如果不存在事务,传播特性又是REQUIRED或NEW或NESTED,将会先挂起null,这个挂起方法我们后面再讲,然后创建一个DefaultTransactionStatus ,并将其标记为新事务,然后执行doBegin(transaction, definition);这个方法也是一个关键方法
神秘又关键的status对象
TransactionStatus接口
public interface TransactionStatus extends SavepointManager, Flushable {
// 返回当前事务是否为新事务(否则将参与到现有事务中,或者可能一开始就不在实际事务中运行)
boolean isNewTransaction();
// 返回该事务是否在内部携带保存点,也就是说,已经创建为基于保存点的嵌套事务。
boolean hasSavepoint();
// 设置事务仅回滚。
void setRollbackOnly();
// 返回事务是否已标记为仅回滚
boolean isRollbackOnly();
// 将会话刷新到数据存储区
@Override
void flush();
// 返回事物是否已经完成,无论提交或者回滚。
boolean isCompleted();
}
再来看看实现类DefaultTransactionStatus
DefaultTransactionStatus
public class DefaultTransactionStatus extends AbstractTransactionStatus { //事务对象
@Nullable
private final Object transaction; //事务对象
private final boolean newTransaction; private final boolean newSynchronization; private final boolean readOnly; private final boolean debug; //事务对象
@Nullable
private final Object 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;
} //略...
}
我们看看这行代码 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 这里是构造一个status对象的方法
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);
}
实际上就是封装了事务属性definition,新创建的transaction,并且将事务状态属性设置为新事务,最后一个参数为被挂起的事务。
简单了解一下关键参数即可:
第二个参数transaction:事务对象,在一开头就有创建,其就是事务管理器的一个内部类。
第三个参数newTransaction:布尔值,一个标识,用于判断是否是新的事务,用于提交或者回滚方法中,是新的才会提交或者回滚。
最后一个参数suspendedResources:被挂起的对象资源,挂起操作会返回旧的holder,将其与一些事务属性一起封装成一个对象,就是这个suspendedResources这个对象了,它会放在status中,在最后的清理工作方法中判断status中是否有这个挂起对象,如果有会恢复它
接着我们来看看关键代码 doBegin(transaction, definition);
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null; try {
// 判断如果transaction没有holder的话,才去从dataSource中获取一个新连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//通过dataSource获取连接
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 所以,只有transaction中的holder为空时,才会设置为新holder
// 将获取的连接封装进ConnectionHolder,然后封装进transaction的connectionHolder属性
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
//设置新的连接为事务同步中
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
//conn设置事务隔离级别,只读
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);//DataSourceTransactionObject设置事务隔离级别 // 如果是自动提交切换到手动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 如果只读,执行sql设置事务只读
prepareTransactionalConnection(con, definition);
// 设置connection持有者的事务开启状态
txObject.getConnectionHolder().setTransactionActive(true); int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// 设置超时秒数
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
} // 将当前获取到的连接绑定到当前线程
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.dataSource);
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
conn设置事务隔离级别,只读
@Nullable
public static Integer prepareConnectionForTransaction(Connection con, @Nullable TransactionDefinition definition)
throws SQLException { Assert.notNull(con, "No Connection specified"); // Set read-only flag.
// 设置数据连接的只读标识
if (definition != null && definition.isReadOnly()) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Setting JDBC Connection [" + con + "] read-only");
}
con.setReadOnly(true);
}
catch (SQLException | RuntimeException ex) {
Throwable exToCheck = ex;
while (exToCheck != null) {
if (exToCheck.getClass().getSimpleName().contains("Timeout")) {
// Assume it's a connection timeout that would otherwise get lost: e.g. from JDBC 4.0
throw ex;
}
exToCheck = exToCheck.getCause();
}
// "read-only not supported" SQLException -> ignore, it's just a hint anyway
logger.debug("Could not set JDBC Connection read-only", ex);
}
} // Apply specific isolation level, if any.
// 设置数据库连接的隔离级别
Integer previousIsolationLevel = null;
if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
if (logger.isDebugEnabled()) {
logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " +
definition.getIsolationLevel());
}
int currentIsolation = con.getTransactionIsolation();
if (currentIsolation != definition.getIsolationLevel()) {
previousIsolationLevel = currentIsolation;
con.setTransactionIsolation(definition.getIsolationLevel());
}
} return previousIsolationLevel;
}
我们看到都是通过 Connection 去设置
线程变量的绑定
我们看 doBegin 方法的47行,将当前获取到的连接绑定到当前线程,绑定与解绑围绕一个线程变量,此变量在TransactionSynchronizationManager
类中:
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
这是一个 static final 修饰的 线程变量,存储的是一个Map,我们来看看47行的静态方法,bindResource
public static void bindResource(Object key, Object value) throws IllegalStateException {
// 从上面可知,线程变量是一个Map,而这个Key就是dataSource
// 这个value就是holder
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
// 获取这个线程变量Map
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
// 将新的holder作为value,dataSource作为key放入当前线程Map中
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
} Thread.currentThread().getName() + "]");
}
// 略...
}
扩充知识点
这里再扩充一点,mybatis中获取的数据库连接,就是根据 dataSource 从ThreadLocal中获取的
以查询举例,会调用Executor#doQuery方法:
最终会调用DataSourceUtils#doGetConnection获取,真正的数据库连接,其中TransactionSynchronizationManager中保存的就是方法调用前,spring增强方法中绑定到线程的connection,从而保证整个事务过程中connection的一致性
我们看看TransactionSynchronizationManager.getResource(Object key)这个方法
@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;
} @Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
就是从线程变量的Map中根据 DataSource获取 ConnectionHolder
已经存在的事务
前面已经提到,第一次事务开始时必会新创一个holder然后做绑定操作,此时线程变量是有holder的且avtive为true,如果第二个事务进来,去new一个transaction之后去线程变量中取holder,holder是不为空的且active是为true的,所以会进入handleExistingTransaction方法:
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 1.NERVER(不支持当前事务;如果当前事务存在,抛出异常)报错
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 2.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);
// 这里可以看到,第二个参数transaction传了一个空事务,第三个参数false为旧标记
// 最后一个参数就是将前面挂起的对象封装进新的Status中,当前事务执行完后,就恢复suspendedResources
return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 3.REQUIRES_NEW挂起当前事务,创建新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 将原事务挂起,此时新建事务,不与原事务有关系
// 会将transaction中的holder设置为null,然后解绑!
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// new一个status出来,传入transaction,并且为新事务标记,然后传入挂起事务
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 这里也做了一次doBegin,此时的transaction中holer是为空的,因为之前的事务被挂起了
// 所以这里会取一次新的连接,并且绑定!
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
}
// 如果此时的传播特性是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() + "]");
}
// 这里如果是JTA事务管理器,就不可以用savePoint了,将不会进入此方法
if (useSavepointForNestedTransaction()) {
// 这里不会挂起事务,说明NESTED的特性是原事务的子事务而已
// new一个status,传入transaction,传入旧事务标记,传入挂起对象=null
DefaultTransactionStatus status =prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 这里是NESTED特性特殊的地方,在先前存在事务的情况下会建立一个savePoint
status.createAndHoldSavepoint();
return status;
}
else {
// JTA事务走这个分支,创建新事务
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
} // 到这里PROPAGATION_SUPPORTS 或 PROPAGATION_REQUIRED或PROPAGATION_MANDATORY,存在事务加入事务即可,标记为旧事务,空挂起
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
对于已经存在事务的处理过程中,我们看到了很多熟悉的操作,但是,也有些不同的地方,函数中对已经存在的事务处理考虑两种情况。
(1)PROPAGATION_REQUIRES_NEW表示当前方法必须在它自己的事务里运行,一个新的事务将被启动,而如果有一个事务正在运行的话,则在这个方法运行期间被挂起。而Spring中对于此种传播方式的处理与新事务建立最大的不同点在于使用suspend方法将原事务挂起。 将信息挂起的目的当然是为了在当前事务执行完毕后在将原事务还原。
(2)PROPAGATION_NESTED表示如果当前正有一个事务在运行中,则该方法应该运行在一个嵌套的事务中,被嵌套的事务可以独立于封装事务进行提交或者回滚,如果封装事务不存在,行为就像PROPAGATION_REQUIRES_NEW。对于嵌入式事务的处理,Spring中主要考虑了两种方式的处理。
- Spring中允许嵌入事务的时候,则首选设置保存点的方式作为异常处理的回滚。
- 对于其他方式,比如JTA无法使用保存点的方式,那么处理方式与PROPAGATION_ REQUIRES_NEW相同,而一旦出现异常,则由Spring的事务异常处理机制去完成后续操作。
对于挂起操作的主要目的是记录原有事务的状态,以便于后续操作对事务的恢复
小结
到这里我们可以知道,在当前存在事务的情况下,根据传播特性去决定是否为新事务,是否挂起当前事务。
NOT_SUPPORTED :会挂起事务,不运行doBegin方法传空transaction
,标记为旧事务。封装status
对象:
return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources)
REQUIRES_NEW :将会挂起事务且运行doBegin方法,标记为新事务。封装status
对象:
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
NESTED :不会挂起事务且不会运行doBegin方法,标记为旧事务,但会创建savePoint
。封装status
对象:
DefaultTransactionStatus status =prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
其他事务例如REQUIRED :不会挂起事务,封装原有的transaction不会运行doBegin方法,标记旧事务,封装status
对象:
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
挂起
对于挂起操作的主要目的是记录原有事务的状态,以便于后续操作对事务的恢复:
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// 这里是真正做挂起的方法,这里返回的是一个holder
suspendedResources = doSuspend(transaction);
}
// 这里将名称、隔离级别等信息从线程变量中取出并设置对应属性为null到线程变量
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);
// 将事务各个属性与挂起的holder一并封装进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;
}
}
@Override
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 将transaction中的holder属性设置为空
txObject.setConnectionHolder(null);
// ConnnectionHolder从线程变量中解绑!
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
我们来看看 unbindResource
private static Object doUnbindResource(Object actualKey) {
// 取得当前线程的线程变量Map
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
// 将key为dataSourece的value移除出Map,然后将旧的Holder返回
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
// 如果此时map为空,直接清除线程变量
if (map.isEmpty()) {
resources.remove();
}
// Transparently suppress a ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
value = null;
}
if (value != null && logger.isTraceEnabled()) {
logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +
Thread.currentThread().getName() + "]");
}
// 将旧Holder返回
return value;
}
可以回头看一下解绑操作的介绍。这里挂起主要干了三件事:
- 将transaction中的holder属性设置为空
- 解绑(会返回线程中的那个旧的holder出来,从而封装到SuspendedResourcesHolder对象中)
- 将SuspendedResourcesHolder放入status中,方便后期子事务完成后,恢复外层事务
spring5 源码深度解析----- 事务增强器(100%理解事务)的更多相关文章
- spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
@Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供 ...
- spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)
此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理. 自定义标签 对于Spring中事务功能的代码分析,我们首先从配置文件开始人手,在配置文件中有这样一个配置 ...
- spring5 源码深度解析----- @Transactional注解的声明式事物介绍(100%理解事务)
面的几个章节已经分析了spring基于@AspectJ的源码,那么接下来我们分析一下Aop的另一个重要功能,事物管理. 事务的介绍 1.数据库事物特性 原子性多个数据库操作是不可分割的,只有所有的操作 ...
- spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)
上一篇文章讲解了获取事务,并且通过获取的connection设置只读.隔离级别等,这篇文章讲解剩下的事务的回滚和提交 回滚处理 之前已经完成了目标方法运行前的事务准备工作,而这些准备工作最大的目的无非 ...
- spring5 源码深度解析-----ApplicationContext容器refresh过程
在之前的博文中我们一直以BeanFactory接口以及它的默认实现类XmlBeanFactory为例进行分析,但是Spring中还提供了另一个接口ApplicationContext,用于扩展Bean ...
- spring5 源码深度解析----- 创建AOP代理之获取增强器
在上一篇的博文中我们讲解了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类到底做了什么工作来完成AOP的操作呢?首先我们看看 ...
- spring5 源码深度解析----- AOP目标方法和增强方法的执行(100%理解AOP)
上一篇博文中我们讲了代理类的生成,这一篇主要讲解剩下的部分,当代理类调用时,目标方法和代理方法是如何执行的,我们还是接着上篇的ReflectiveMethodInvocation类Proceed方法来 ...
- spring5 源码深度解析----- AOP的使用及AOP自定义标签
我们知道在面向对象OOP编程存在一些弊端,当需要为多个不具有继承关系的对象引入同一个公共行为时,例如日志,安全检测等,我们只有在每个对象里引入公共行为,这样程序中就产生了大量的重复代码,所以有了面向对 ...
- spring5 源码深度解析----- AOP代理的生成
在获取了所有对应bean的增强后,便可以进行代理的创建了.回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下所示: protected static fi ...
随机推荐
- 深度递归必须知道的尾调用(Lambda)
引导语 本文从一个递归栈溢出说起,像大家介绍一下如何使用尾调用解决这个问题,以及尾调用的原理,最后还提供一个解决方案的工具类,大家可以在工作中放心用起来. 递归-发现栈溢出 现在我们有个需求,需要计算 ...
- 51NOD---逆序对(树状数组 + 归并排序)
1019 逆序数 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称 ...
- 云开发数据库VS传统数据库丨云开发101
云开发数据库与传统数据库的不同 在小程序·云开发中,最核心的便是三大组件:数据库.云存储和云函数,从今天开始,我们将开始隔日更的专栏文章,云开发101,在第一周,我们将从最最核心的数据库开始说起. 云 ...
- CentOS 7.3 安装 libsodium 1.0.18
出现configure: error: The Sodium crypto library libraries not found.错误或者notfound 1.下载并解压 wget https:// ...
- maven学习笔记(超详细总结)
目录 项目管理利器--maven 第1章 maven概述 1-1 项目管理利器-maven简介 1.1.1 什么是maven 1.1.2 什么是依赖管理 1.1.3 传统项目的依赖管理 1.1.4 m ...
- NUMA导致的MySQL服务器SWAP问题分析
[作者] 王栋:携程技术保障中心数据库专家,对数据库疑难问题的排查和数据库自动化智能化运维工具的开发有强烈的兴趣. [问题描述] 我们知道当mysqld进程使用到SWAP时,就会严重影响到MySQL的 ...
- 正则表达式(RegExp)
前言:先来了解一下基础知识.再细说正则表达式~ 转义字符 ---- \ 转义字符会将与之相邻的字符转换含义. 例如说,希望在一个字符串中输出 “ 号,那么就可以使用在双引号前加入 \ ,这样就能 ...
- apache ignite系列(四):持久化
ignite持久化与固化内存 1.持久化的机制 ignite持久化的关键点如下: ignite持久化可防止内存溢出导致数据丢失的情况: 持久化可以定制化配置,按需持久化; 持久化能解决在大量缓存数据情 ...
- HIve实战分析Hadoop的日志
1.日志格式分析首先分析 Hadoop 的日志格式, 日志是一行一条, 日志格式可以依次描述为:日期.时间.级别.相关类和提示信息.如下所示: -03-06 15:23:48,132 INFO org ...
- HABSE表结构理解
也分为行列,行是索引,锁定数据,查找数据只能通过行 列:建表时必须知道列族,真实列(列簇)在插入数据时候可以指定 查找指定列,必须带列族,列族1:name