Transaction rolled back because it has been marked as rollback-only问题解决

1、背景

在我们的日常开发中,经常会存在在一个Service层中调用另外一个Service层的方法。比如:我们有一个TaskService,里面有一个execTask方法,且这个方法存在事务,这个方法在执行完之后,需要调用LogService的insertLog方法记录一条日志,这个方法上也有事务,不管日志记录成功还是失败,都不能影响execTask方法的执行。因此我们很容易写出如下代码。

java 复制代码
@Transactional
public void execTaskV1(){
    log.info("开始执行任务");
    try {
        logService.insertLogV1();
    } catch (Exception e) {
        log.error("添加日志出现错误");
    }
    log.info("完成任务执行");
}

思考: 上方的代码,如果insertLogV1跑出了异常,execTaskV1方法的事务可以正常提交吗?

2、异常是如何实现出现的

1、了解Spring事务的传播属性

传播行为 描述 应用场景 行为特点
Propagation.REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则启动一个新的事务。 大多数场景,如多个方法需要在同一个事务中完成。 - 如果当前事务存在,方法执行在当前事务上下文中。 - 如果当前事务不存在,创建新事务。
Propagation.SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。 对事务支持没有强制要求的场景,如只读查询。 - 如果当前事务存在,方法执行在当前事务上下文中。 - 如果当前事务不存在,以非事务方式执行。
Propagation.MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 必须在一个已存在的事务中执行的场景。 - 必须在已有事务中执行,否则抛出 IllegalTransactionStateException
Propagation.REQUIRES_NEW 每次调用该方法时都会启动一个新的事务。当前事务(如果有)会被挂起。 需要独立事务的场景,如日志记录或独立的业务操作。 - 总是创建新事务。 - 当前事务(如果有)会被挂起,直到新事务完成。
Propagation.NOT_SUPPORTED 总是以非事务方式执行,并且暂停当前事务(如果有)。 不需要事务的场景,如简单的查询操作。 - 总是以非事务方式执行。 - 暂停当前事务(如果有)。
Propagation.NEVER 总是以非事务方式执行,如果当前存在事务,则抛出异常。 严格禁止事务的场景,如某些非事务性操作。 - 必须在非事务上下文中执行,否则抛出 TransactionException
Propagation.NESTED 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则启动一个新的事务。 需要嵌套事务的场景,如复杂的业务流程中需要独立的回滚点。 - 如果当前事务存在,创建一个嵌套事务(依赖于数据库支持)。 - 如果当前事务不存在,创建新事务。

2、模拟异常出现

Transaction rolled back because it has been marked as rollback-only 这个异常在上述的案例中是如何实现的呢?

从上图中可知,出现了Transaction rolled back because it has been marked as rollback-only这个异常,那么这个异常是如何出现的呢?

其实这个是和Spring事务的传播属性Propagation有关。

默认情况下@Transaction的传播属性是Propagation.REQUIRED, 即如果当前存在事务,则加入该事务;如果当前没有事务,则启动一个新的事务。 在我们的例子中,事务的隔离级别都是Propagation.REQUIRED,即是在同一个事务中,因此insertLogV1方法抛出异常后,虽然上层捕获到了,但其实这个时候这个事务已经被标记成回滚状态了,因此事务无法提交成功。

如何解决: 只需要修改insertLogV1事务的传播属性为Propagation.REQUIRES_NEW即可。

3、完整代码

完整代码-https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-transaction-v1

相关推荐
m0_740043733 分钟前
【无标题】
java·spring boot·spring·spring cloud·微服务
编程彩机1 小时前
互联网大厂Java面试:从微服务到分布式缓存的技术场景解析
redis·spring cloud·消息队列·微服务架构·openfeign·java面试·分布式缓存
Anastasiozzzz8 小时前
Nginx和Ribbon的区别
后端·spring cloud·ribbon
码农水水8 小时前
从 OpenFeign 到 RestClient:Spring Cloud 新时代的轻量化 HTTP 调用方案
java·运维·后端·spring·http·spring cloud·面试
what丶k1 天前
SpringBoot3 配置文件使用全解析:从基础到实战,解锁灵活配置新姿势
java·数据库·spring boot·spring·spring cloud
小信丶1 天前
@Activate 注解详解:应用场景与实战示例
java·spring boot·后端·spring·spring cloud·微服务·dubbo
编程彩机1 天前
互联网大厂Java面试:从Spring MVC到微服务架构场景解析
java·spring cloud·微服务·分布式事务·spring mvc
鸽鸽程序猿1 天前
【JavaEE】【SpringCloud】 熔断和限流 Alibaba Sentinel
spring cloud·java-ee·sentinel
Roye_ack1 天前
【微服务 Day8】SpringCloud实战开发(Elasticsearch02 + DSL查询、聚合)
spring cloud·微服务·架构·dsl·聚合
努力也学不会java1 天前
【Spring Cloud】注册中心-Nacos
java·人工智能·spring boot·后端·spring·spring cloud