> 文章列表 > 事务报错解决:Transaction rolled back because it has been marked as rollback-only

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

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

事务报错问题

  • 关于Transaction rolled back because it has been marked as rollback-only的报错分析
    • 代码分析
    • 问题分析
    • 问题解决

关于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

代码分析

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

@Overridepublic 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()))

    @Overridepublic 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 (每个事务调用提交或回滚的次数不要超过一次)

问题解决

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

素描画