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

我们知道spring事务回滚的机制是需要捕获运行时异常,当然也可以使用rollbackfor指定特殊的unchecked异常。如下代码所示:

@Transactional
@Override
public int getTran() {

    teamEnrollDao.save(tenroll);

    userEnrollDao.save(uenroll);

    return 1;
}

上面service方法内没有捕获异常,因为spring事务回滚需要抛出异常才可以。但如果需要捕获异常错误记录日志,可以在catch代码记录日志后再抛出新的运行时异常即可。

但是下面的代码,让我有点费解,明明捕获了第二个save方法的异常,而且没有抛出新的运行时异常,按理这个时候第一个save方法是可以正常执行的,但是结果却回退了,而且该方法退出时还会抛出异常:
Transaction rolled back because it has been marked as rollback-only

@Transactional
@Override
public int getTran() {
    teamEnrollDao.save(tenroll);
    try {
        userEnrollDao.save(uenroll);
    } catch (Exception e) {
        logger.error(e.getMessage());
    }

    return 1;
}

这个是什么原因导致的呢,找了一些资料后算是有点头绪了。
@Transactional注解默认的事务传播属性是REQUIRED,service方法开始时会创建事务,第一save方法执行时发现当前有事务就直接加入,第二个save方法执行时发现当前有事务也直接加入,即所有方法执行都是在同一个事务中。此时若第二个save方法执行时有异常,这时spring事务会标记这个事务需要回滚,虽然异常在service方法内被捕获了,但是实际上基于事务的传播性,service和两个save方法用的是同一个事务,也即service方法的事务被标记为需要回滚。当捕获异常后service方法内代码继续执行,正常返回的时候,spring进行事务提交,这个时候它发现这个事务已经被标记为需要回滚了。所以这个时候spring事务就抛出异常:
Transaction rolled back because it has been marked as rollback-only

其实这个问题的根本原因就是spring事务的传播属性导致的,要解决这种现象可以在第二个save方法上面加入
@Transactional(propagation = Propagation.REQUIRES_NEW),这时第二个save方法执行时是一个新的单独的事务,这个事务的执行不会影响到service方法的事务执行。所以当service方法捕获这个异常时,service方法事务不会发现这个异常,即service方法事务不会回滚,第一个save方法就会正常执行;若service方法不捕获这个异常或者捕获异常后抛出一个新的运行时异常,这个时候异常就会被service方法事务发现,从而回滚service方法事务,第一个save方法就不会正常执行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值