事务报错解决:Transaction rolled back because it has been marked as rollback-only

文章分析了一个在执行数据库删除操作时遇到的Spring事务回滚异常问题。代码中,在尝试提交事务时遇到因内部操作失败已标记为回滚的事务,导致UnexpectedRollbackException和重复提交事务的错误。解决方案是修正引发事务回滚的代码部分,确保没有错误发生,从而允许正常提交事务。

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

关于Transaction rolled back because it has been marked as rollback-only的报错分析

执行删除操作时使用事务报错,报错信息如下
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

代码分析

调用代码如下:简单描述一下业务逻辑,数据库实体中存在订购单元,因此在执行删除数据库时需要先删除订购单元,删除成功后再删除数据库。

@Override
    public boolean delete(Long id) {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(TransactionDefinition.withDefaults());
        int result = 0;
        try {
        
        	 //-------------业务逻辑开始-------------
            //删除订购单元
            List<EbookCollectionUnitBean> collectionUnitBeans = ebookCollectionUnitMapper.selectList(Wrappers.<EbookCollectionUnitBean>lambdaQuery()
                    .eq(EbookCollectionUnitBean::getEbookCollectionId, id));
            if (CollectionUtils.isNotEmpty(collectionUnitBeans)) {
                collectionUnitBeans.stream().forEach(x -> eBookCollectionUnitService.delete(x.getId()));
            }
            //删除数据库
            result = ebookCollectionMapper.deleteById(id);
            //-------------业务逻辑结束-------------

            //事务提交
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
           dataSourceTransactionManager.rollback(transactionStatus);
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
        return result > 0;
    }

上面的业务代码中调用删除订购单元的程序:eBookCollectionUnitService.delete(x.getId()))

    @Override
    public Boolean delete(Long id) {

        boolean result = false;
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(TransactionDefinition.withDefaults());
        try {
            EbookCollectionUnitBean ebookCollectionUnitBean = ebookCollectionUnitMapper.selectById(id);
            /**
             * 如果 数字资源采购库 的收录时间修改,则更改所属期刊下的所有文章 标记为馆藏资源
             */
            if (ebookCollectionUnitBean.getPurchaseFlag() == 1) {
                updateUnitPaperSource(ebookCollectionUnitBean, null);
            }

            result = ebookCollectionUnitMapper.deleteById(id) > 0;

            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            log.error("===delete error info", e);
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return result;
    }

问题分析

直接说结论,第二段的代码在更新数据库时报错导致事务回滚。
第一段代码中的事务执行到
dataSourceTransactionManager.commit(transactionStatus);的时候就会发现
Transaction rolled back because it has been marked as rollback-only(事务已经是回滚状态)因为它被标记成了只回滚,所以只能执行select查询,insert/update/delete操作必然回滚
此时执行事务提交
dataSourceTransactionManager.commit(transactionStatus);
必然会报错,因此被catch捕捉到,同时catch中又有事务回滚的代码
dataSourceTransactionManager.rollback(transactionStatus);
所以又会引发第二个报错:
Transaction is already completed - do not call commit or rollback more than once per transaction (每个事务调用提交或回滚的次数不要超过一次)

问题解决

可知由于第二段代码中报错导致事务回滚,修改业务代码即可解决此问题。此时如果调用不报错,那么第一段代码即可成功进行事务提交,第二个报错也会随之解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐州蔡徐坤

又要到饭了兄弟们

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值