Spring事务捕获异常后依旧回滚,2024年Java开发进阶课程

final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

//注解事务会走这里

if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {

// Standard transaction demarcation with getTransaction and commit/rollback calls.

//开启事务

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;

}

复制代码

不重要的代码我已经省略了,好我们来看这个流程,上面这段代码很明显反应出了,当我们程序执行过程中抛出了异常时会调用到completeTransactionAfterThrowing的回滚操作,如果没有发生异常最终会调用事务提交commitTransactionAfterReturning, 我们来分析一下

img

正常情况是C发生异常,并且执行到了completeTransactionAfterThrowing事务回滚,但是因为不是新创建的事务,而是加入的事务所以并不会触发回滚操作,而在A中捕获了该异常,并且最终走到commitTransactionAfterReturning事务提交,事实是这样的吗?

事实上就是这样的,那就奇怪了,我明明提交了,怎么反而回滚了,我们继续往下看

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {

// Use defaults if no transaction definition given.

TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

//重点看… DataSourceTransactionObject拿到对象

Object transaction = doGetTransaction();

boolean debugEnabled = logger.isDebugEnabled();

//第一次进来connectionHolder为空的, 所以不存在事务

if (isExistingTransaction(transaction)) {

// Existing transaction found -> check propagation behavior to find out how to behave.

//如果不是第一次进来, 则会走这个逻辑

return handleExistingTransaction(def, transaction, debugEnabled);

}

// Check definition settings for new transaction.

if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

throw new InvalidTimeoutException(“Invalid transaction timeout”, def.getTimeout());

}

// No existing transaction found -> check propagation behavior to find out how to proceed.

if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

throw new IllegalTransactionStateException(

“No existing transaction found for transaction marked with propagation ‘mandatory’”);

}

//第一次进来大部分会走这里(传播属性是 Required | Requested New | Nested)

else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

//先挂起

SuspendedResourcesHolder suspendedResources = suspend(null);

if (debugEnabled) {

logger.debug(“Creating new transaction with name [” + def.getName() + "]: " + def);

}

try {

//开启事务

return startTransaction(def, transaction, debugEnabled, suspendedResources);

} catch (RuntimeException | Error ex) {

resume(null, suspendedResources);

throw ex;

}

} else {

// Create “empty” transaction: no actual transaction, but potentially synchronization.

if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {

logger.warn("Custom isolation level specified but no actual transaction initiated; " +

"isolation level will effectively be ignored: " + def);

}

boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);

}

}

复制代码

这段代码是开启事务的代码,我们来看,当我们A第一次走进来的时候,此时是没有事务的,所以isExistingTransaction方法不成立,往下走,因为我们的传播机制是REQUIRED,所以我们会走到startTransaction方法中

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

boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

//创建一个新的事务状态, 注意这里的newTransaction 属性为true

DefaultTransactionStatus status = newTransactionStatus(

definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

//开启事务

doBegin(transaction, definition);

//开启事务后, 改变事务状态

prepareSynchronization(status, definition);

return status;

}

复制代码

好这里我们只需要关注一个点那就是newTransactionStatus的第三个参数newTransaction,只有当我们新创建一个事务的时候才会为true这个属性很重要,我们后续还会用到它

好了,到这里第一次的事务开启就已经完成了,然后我们会调用业务逻辑,当调用insertB时,又会走到getTransaction,我们继续来看它,此时isExistingTransaction就可以拿到值了,因为A已经帮我们创建好了事务,此时会调用到handleExistingTransaction方法

//如果第二次进来还是PROPAFGATION_REQUIRED, 走这里, newTransation为false

return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

复制代码

针对REQUIRED有用的代码就这一句,其他全部不用看,同样的我们看到第三个参数newTransaction,这里是false了,说明是加入了之前的事务,而不是自己新创建的,然后执行业务代码,最后走到commit,我们来看看commit中做了什么

//如果有回滚点

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();

}

复制代码

它什么事情都没有做,为什么?因为我们的newTransaction不为true,所以当我们的代码在operate方法全部执行完以后才会走到这里

好接下来我们来看insertC,前面的流程都一模一样,我们直接看到回滚代码

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {

try {

boolean unexpectedRollback = unexpected;

try {

triggerBeforeCompletion(status);

if (status.hasSavepoint()) {

if (status.isDebug()) {

logger.debug(“Rolling back transaction to savepoint”);

}

status.rollbackToHeldSavepoint();

} else if (status.isNewTransaction()) {

if (status.isDebug()) {

logger.debug(“Initiating transaction rollback”);

}

doRollback(status);

} else {

// Participating in larger transaction

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

写在最后

可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。

复习一周,字节跳动三场技术面+HR面,不小心拿了offer

复习一周,字节跳动三场技术面+HR面,不小心拿了offer

上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。

[外链图片转存中…(img-0RJUaxyd-1712767262978)]

[外链图片转存中…(img-LZ2i8ovs-1712767262978)]

上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-AAtRLlZj-1712767262978)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值