Spring事务提交,回滚,传播属性源码分析

在j2ee开发中实现事务的方式有编程式事务和基于aop的注解事务。编程事务通过手写jdbc,手动获取数据库连接,手动处理commit和rollback,这种方式有大量重复的代码和业务代码耦合,而且jdbc原生不支持事务的传播属性;

为了解决以上这些问题,Spring使用基于Aop注解式事务解决大量重复代码耦合问题,也基于注解的方式实现了一套事务传播处理机制。

Aop注解式事务的切入原理在前面已经分析了,这里看一下事务是怎么开启,commit,rollbak, 事务传播机制spring是怎么实现的。

1.从Aop事务的增强切入点开始

TransactionInterceptor,实现了MethodInterceptor和Advice接口代表Aop的一个增强,MethodInterceptor这个在创建代理的时候会被jdk动态代理或cglib代理类回调。业务方法被封装在MethodInvocation这个参数里。这个类继承了TransactionAspectSupport,this.invokeWithinTransaction(var10001, targetClass, invocation::proceed); 其实调用的是TransactionAspectSupport类的protected方法invokeWithinTransaction, 这个方法开启了spring进行事务增强的逻辑。

2.TransactionAspectSupport类的方法invokeWithinTransaction

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    TransactionAttributeSource tas = this.getTransactionAttributeSource();
    TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
     //获取数据库TransactionManager 默认配置的是DatasourceTransactionManager PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
    String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
    Object result;
    if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
 //这里datasourceTransactionManager没有实现CallbackPreferringPlatformTransactionManager这个分支不用看
        TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

        try {
            result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> {
                TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                Object var9;
                try {
                    Object var8 = invocation.proceedWithInvocation();
                    return var8;
                } catch (Throwable var13) {
                    if (txAttr.rollbackOn(var13)) {
                        if (var13 instanceof RuntimeException) {
                            throw (RuntimeException)var13;
                        }

                        throw new TransactionAspectSupport.ThrowableHolderException(var13);
                    }

                    throwableHolder.throwable = var13;
                    var9 = null;
                } finally {
                    this.cleanupTransactionInfo(txInfo);
                }

                return var9;
            });
            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            } else {
                return result;
            }
        } catch (TransactionAspectSupport.ThrowableHolderException var19) {
            throw var19.getCause();
        } catch (TransactionSystemException var20) {
            if (throwableHolder.throwable != null) {
                this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                var20.initApplicationException(throwableHolder.throwable);
            }

            throw var20;
        } catch (Throwable var21) {
            if (throwableHolder.throwable != null) {
                this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            }

            throw var21;
        }
    } else {//只要看这个分支就可以了
        //这里创建事务,即开启了事务,把事务信息放进txInfo
        TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        result = null;

        try {
            result = invocation.proceedWithInvocation();//执行业务方法
        } catch (Throwable var17) {
            this.completeTransactionAfterThrowing(txInfo, var17);//如果抛异常则回滚
            throw var17;
        } finally {
            this.cleanupTransactionInfo(txInfo);//调用业务方法结束后清除线程里的本次事务信息
        }

        this.commitTransactionAfterReturning(txInfo);//正常结束提交事务
        return result;
    }
}
public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

TransactionAttributeSource和TransactionAttribute封装了@Transaciton事务的配置信息包括传播属性,rollback的异常,隔离级别,超时时间等。PlatformTransactionManager是事务管理者接口,这个接口getTransaction,commit,rollback方法,getTransaction返回值TransactionStatus这个类封装事务的状态信息。PlatformTransactionManager具体实现有DatasourceTransactionManager,PlatformTransactionManager等,Spring默认大多数用的是DatasourceTransactionManager。DatasourceTransactionManager没有实现CallbackPreferringPlatformTransactionManager这个接口所有上面代码的第一个分支没走到,只要看else这个分支就可以了。 TransactionAspectSupport.TransactionInfo 这个类封装了事务的很多信息,包括定义,状态等信息。下面分析红色部分的调用方法

3. TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification); 这个方法是获取事务和数据库连接。

protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
        txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
             //这里创建事务,根据传播属性决定是否创建数据库连接,新事务会创建数据库连接。
            status = tm.getTransaction((TransactionDefinition)txAttr);
        } else if (this.logger.isDebugEnabled()) {
            this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
        }
    }
    //这个方法绑定当前事务信息到当前线程里,面用threadlocal实现。在spring的事务框架上thradlocal用的很多,包括数据库连接和事务属性都放在threadlocal里,theadlocal主要用来保存一个线程中的所有事务。一个线程的栈里方法有多个,可能配置了多个事务,这些事务有些开启了新的数据库连接,有些没开启只是引用了其他事务的数据库连接,这些都放在threadlocal里,整个事务传播属性也是基于threadlocal实现的。
    return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}

4.status = tm.getTransaction((TransactionDefinition)txAttr); 这句根据事务定义开启事务获取状态数据库连接。

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    Object transaction = this.doGetTransaction();//创建事务
    boolean debugEnabled = this.logger.isDebugEnabled();
    if (definition == null) {
        definition = new DefaultTransactionDefinition();
    }
    //这里判断是否已经存在旧的事务,这里面使用theadlaocl来判断的,如果线程里已经有数据库连接了说明已经存在旧的事务了。
    if (this.isExistingTransaction(transaction)) {
        return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled);//如果已经存在旧的事务就走这里
    } else if (((TransactionDefinition)definition).getTimeout() < -1) {
        throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());
    } else if (((TransactionDefinition)definition).getPropagationBehavior() == 2) {
        throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
    } else if (((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
        if (((TransactionDefinition)definition).getIsolationLevel() != -1 && this.logger.isWarnEnabled()) {
            this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + definition);
        }

        boolean newSynchronization = this.getTransactionSynchronization() == 0;
        return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization, debugEnabled, (Object)null);
    } else {
        AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);
        if (debugEnabled) {
            this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);
        }

        try {
            boolean newSynchronization = this.getTransactionSynchronization() != 2;
            DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            this.doBegin(transaction, (TransactionDefinition)definition);
            this.prepareSynchronization(status, (TransactionDefinition)definition);
            return status;
        } catch (Error | RuntimeException var7) {
            this.resume((Object)null, suspendedResources);
            throw var7;
        }
    }
}
@Override
protected Object doGetTransaction() {
   DataSourceTransactionObject txObject = new DataSourceTransactionObject();
   txObject.setSavepointAllowed(isNestedTransactionAllowed());
   ConnectionHolder conHolder =
         (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
   txObject.setConnectionHolder(conHolder, false);//这里封装了threadloacl从当前线程获取数据库连接
   return txObject;
}
 //如果已经存在旧的事务就走下面这个方法,这个方法根据getPropagationBehavior即传播属性来处理不同的逻辑,现在分析默认情况PROPAGATION_REQUIRED时。
 private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
if (definition.getPropagationBehavior() == 5) {
throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'");
} else {
AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources;
boolean newSynchronization;
if (definition.getPropagationBehavior() == 4) {
if (debugEnabled) {
this.logger.debug("Suspending current transaction");
}

suspendedResources = this.suspend(transaction);
newSynchronization = this.getTransactionSynchronization() == 0;
return this.prepareTransactionStatus(definition, (Object)null, false, newSynchronization, debugEnabled, suspendedResources);
} else if (definition.getPropagationBehavior() == 3) {
if (debugEnabled) {
this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]");
}

suspendedResources = this.suspend(transaction);

try {
newSynchronization = this.getTransactionSynchronization() != 2;
DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
this.doBegin(transaction, definition);
this.prepareSynchronization(status, definition);
return status;
} catch (Error | RuntimeException var7) {
this.resumeAfterBeginException(transaction, suspendedResources, var7);
throw var7;
}
} else {
boolean newSynchronization;
if (definition.getPropagationBehavior() == 6) {
if (!this.isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'");
} else {
if (debugEnabled) {
this.logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}

if (this.useSavepointForNestedTransaction()) {
DefaultTransactionStatus status = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
status.createAndHoldSavepoint();
return status;
} else {
newSynchronization = this.getTransactionSynchronization() != 2;
DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, (Object)null);
this.doBegin(transaction, definition);
this.prepareSynchronization(status, definition);
return status;
}
}
} else {
if (debugEnabled) {
this.logger.debug("Participating in existing transaction");
}

if (this.isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != -1) {
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, "ISOLATION_") : "(unknown)"));
}
}

if (!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is");
}
}
//默认情况会走到最后这个分支,这里没有调用dobeging开启数据库连接而是复用了外围事务的数据库连接,即如果当前存在事务,加入当期事务。
newSynchronization = this.getTransactionSynchronization() != 2;
return this.prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, (Object)null);
}
}
}
}

下面来开一下默认隔离级别PROPAGATION_REQUIRED是如何回滚和提交的。

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

        try {
            this.triggerBeforeCompletion(status);
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    this.logger.debug("Rolling back transaction to savepoint");
                }

                status.rollbackToHeldSavepoint();
            } else if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    this.logger.debug("Initiating transaction rollback");
                }

                this.doRollback(status);
            } else {
                if (status.hasTransaction()) {
                    if (!status.isLocalRollbackOnly() && !this.isGlobalRollbackOnParticipationFailure()) {
                        if (status.isDebug()) {
                            this.logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                        }
                    } else {
                        if (status.isDebug()) {
                            this.logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                        }

                        this.doSetRollbackOnly(status);//由于是默认隔离级别当前如果存在事务,如果出现异常不会回滚只是在事务链上设置回滚标记。
                    }
                } else {
                    this.logger.debug("Should roll back transaction but cannot - no transaction available");
                }

                if (!this.isFailEarlyOnGlobalRollbackOnly()) {
                    unexpectedRollback = false;
                }
            }
        } catch (Error | RuntimeException var8) {
            this.triggerAfterCompletion(status, 2);
            throw var8;
        }

        this.triggerAfterCompletion(status, 1);
        if (unexpectedRollback) {
            throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
        }
    } finally {
        this.cleanupAfterCompletion(status);
    }

}
ublic 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");
    } else {
        DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;
        if (defStatus.isLocalRollbackOnly()) {
            if (defStatus.isDebug()) {
                this.logger.debug("Transactional code has requested rollback");
            }

            this.processRollback(defStatus, false);
        } else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {// defStatus.isGlobaleTollbakcOnly这个方法会判断事务链上是否存在回滚标记,如果存在则当前事务不commit,直接回滚
            if (defStatus.isDebug()) {
                this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
            }

            this.processRollback(defStatus, true);
        } else {
            this.processCommit(defStatus);
        }
    }
}

 下面这个方法是从transaction里查询出回滚标记,transation里封装了threadloal,这里取出的是同一个线程开启的另外一个事务出现异常异常是在processRollback方法this.doSetRollbackOnly(status)里设置的回滚标记。

public boolean isGlobalRollbackOnly() {
    return this.transaction instanceof SmartTransactionObject && ((SmartTransactionObject)this.transaction).isRollbackOnly();
}

至此默认隔离级别下PROPAGATION_REQUIRED,事务提交回滚分析结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值