Transaction rolled back because it has been marked as rollback-only

本文探讨了Spring框架中常见的事务回滚问题Transaction rolled back because it has been marked as rollback-only,详细解释了此错误产生的原因及如何避免。通过示例代码展示了在不同场景下如何正确处理异常以防止事务被标记为仅回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Transaction rolled back because it has been marked as rollback-only

spring 具备多种事务传播机制,最常用的是REQUIRED,即如果不存在事务,则新建一个事务;如果存在事务,则加入现存的事务中。
示例代码如下:

public void A() {
    querySomething(...);
    try {
      B()
    } catch () {
    }
    saveSomethinf();
}

public void B() {
    throw Exception()
}

此时B会和A存在一个事务中。如果B抛出异常没有捕获,即使在A中捕获并处理,仍会发生异常:Transaction rolled back because it has been marked as rollback-only
因为spring会在A捕获异常之前提前捕获到异常,并将当前事务设置为rollback-only,而A觉得对异常进行了捕获,它仍然继续commit,当TransactionManager发现状态为设置为rollback-only时,
则会抛出UnexpectedRollbackException
相关代码在AbstractPlatformTransactonManager.java中:

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);
            return;
        }
        if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
            if (defStatus.isDebug()) {
                logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
            }
            processRollback(defStatus);
            // Throw UnexpectedRollbackException only at outermost transaction boundary
            // or if explicitly asked to.
            if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
                throw new UnexpectedRollbackException(
                        "Transaction rolled back because it has been marked as rollback-only");
            }
            return;
        }

        processCommit(defStatus);
    }

解决方法:
在抛出异常的最原始地方处理异常,即在spring捕获到异常之前处理掉

转载地址:https://github.com/willdonggg/tech-blog/blob/master/Transaction%20rolled%20back%20because%20it%20has%20been%20marked%20as%20rollback-only.md

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值