从零开发短视频电商 Spring事务嵌套问题
创始人
2024-01-21 08:21:59
0

文章目录

      • 问题 marked as rollback-only
      • 原因
      • 解决方案
      • 验证
        • PROPAGATION_REQUIRES_NEW
        • PROPAGATION_NESTED
      • 事务传播方式

问题 marked as rollback-only

问题发现日志出现如下错误 org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

原因

嵌套事务,传播级别设置PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。

在项目中,一般我们都会使用默认的传播方式,这样无论外层事务和内层事务任何一个出现异常,那么所有的sql都不会执行

在嵌套事务场景中,内层事务的sql和外层事务的sql会在外层事务结束时进行提交或回滚。如果内层事务抛出异常e,在内层事务结束时,spring会把事务标记为“rollback-only”。这时如果外层事务捕捉了异常e,那么外层事务方法还会继续执行代码,直到外层事务也结束时,spring发现事务已经被标记为“rollback-only”,但方法却正常执行完毕了,这时spring就会抛出异常。

异常日志错误代码示例

public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {try {b.b()// 这里 滴滴滴,不应该catch,获取catch完,继续向上抛出。} catch (Exception ignore) {}}
}public class ServiceB {@Transactionalpublic void b() {throw new RuntimeException();}
}

当调用a()时,就会报出“rollback-only”异常。

解决方案

方案1: 外层事务不要catch,当然这是在满足需求的前提下哈。

public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {//try {b.b()//} catch (Exception ignore) {//}}
}

方案2: 在外层事务的catch代码块中抛出e.

public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {try {b.b()} catch (Exception ignore) {throw e;}}
}

方案3: 如果希望内层事务回滚,但不影响外层事务提交,需要将内层事务的传播方式指定为PROPAGATION_NESTED。

注:PROPAGATION_NESTED基于数据库savepoint实现的嵌套事务,外层事务的提交和回滚能够控制嵌内层事务,而内层事务报错时,可以返回原始savepoint,外层事务可以继续提交。

public class ServiceB {@Transactional(propagation = Propagation.NESTED)public void b() {throw new RuntimeException();}
}

验证

PROPAGATION_REQUIRES_NEW

public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {// insert ab.b()}
}public class ServiceB {@Transactional(propagation = Propagation.REQUIRES_NEW)public void b() {//insert b;}
}
  • 内事务异常

    public class ServiceB {@Transactional(propagation = Propagation.REQUIRES_NEW)public void b() {//insert b;int i = 1/0;}
    }
    

    结果: 内外都回滚。

  • 外事务异常

    public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {// insert ab.b()int i = 1/0;}
    }
    

    结果: 只有外事务回滚,内事务部回滚

PROPAGATION_NESTED

  • 内事务异常

    public class ServiceB {@Transactional(propagation = Propagation.NESTED)public void b() {//insert b;int i = 1/0;}
    }
    

    结果: 内外都回滚

  • 外事务异常

    public class ServiceA {@Resourceprivate ServiceB b;@Transactionalpublic void a() {// insert ab.b()int i = 1/0;}
    }
    

    结果: 内外都回滚

事务传播方式

事务传播方式说明注意
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是默认的传播方式内外为一个大事务,无论是内事务异常,还是外事务异常,要么都成功要么都失败,是在外事务提交时一起提交的。内外都回滚
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起内事务异常,内外都回滚外事务异常,只有外事务回滚。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。内外都回滚

参考

  • https://cloud.tencent.com/developer/article/1547300

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...