您的位置:首页 > 其它

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

2017-05-16 16:27 543 查看
我们知道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方法就不会正常执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐