SpringCloud跨服务调用失败Seata无法回滚解决办法

遇到的问题

在微服务项目中 有A、B、C三个服务 其中 A调用B服务 ,B调用C, 这些就是跨服务调用了,在A服务中 还调用了一个当前模块执行插入数据的方法(在这里我就叫它为AA 也就是mybatis/spring管理的本地事务)

A服务开启全局事务注解 @GlobalTransactional
B服务注解 @Transactional(propagation = Propagation.REQUIRES_NEW)
C服务注解 @Transactional(propagation = Propagation.REQUIRES_NEW)
AA是所属A模块中的Service的一个方法 也叫本地服务

遇到的问题1) A调用B失败后 A提交了没有回滚

原因 : A调用B失败后 B抛出的异常被 微服务全局捕异常给处理了 并没有抛出异常(再抛还是会被全局捕异常处理的) TM不知道B失败了

这里可以在全局捕异常中将 分布式事务关闭

  /**
     * 如果开启分布式事务,就设置response.status = 500,seata的tm(事务管理器)
     * 并主动回滚
     *
     */
    private static void setRespErrStatus(HttpServletResponse response) {

        //如果开启分布式事务,设置错误状态码,让事务回滚
        if (StringUtils.isNotBlank(RootContext.getXID())) {
            log.error("全局捕异常 捕获到Seata " + " 事务id-------------API--------->" + RootContext.getXID());
            log.error("全局捕异常 捕捉到Seata 事务" + RootContext.getXID() + " 抛出异常 设置response 状态码为 500 ");
            log.error("全局捕获到 Seata异常 全局回滚");
            try {
                response.setStatus(500);
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
                log.error(" 数据提交失败");
            } catch (TransactionException e) {
                log.error(" 捕获seata异常·不处理");
            }
        } else {
            response.setStatus(200);
        }
    }


遇到的问题2)B调用C失败后 AB都提交了没有回滚

原因 : C服务虽然加了 @Transactional(propagation = Propagation.REQUIRES_NEW) 这个在TM没有注册进来(听说是Seata中的bug 博主没有去复现这个问题 这个需要我们调用 RootContext.bind(xid); 进行绑定 )

在Feign调用前 判断 xid是否为空 如果不为空则将 xid绑定

	String xid =RootContext.getXID() ; //获取 xid 
    RootContext.bind(xid); //绑定 xid

遇到的问题3)A调用AA失败后 ABC都提交了没有回滚

原因 : 这个是因为分布式事务调用是正常的,只是本地事务失败了 所有分布式事务都提交了,本地事务未提交 ()

遇到的问题4)ABC服务都失败了,ABC事务回滚了 AA提交了

原因 这个是因为分布式事务调用失败, AA本地事务没有加入到分布式事务中去导致的

    String xid =RootContext.getXID() ;
      xxService.insertScoresGoodInfos(sSysProjectMenu.getPath(),xid);


    @Override
    public int insertScoresGoodInfos(String sysType  ,String xid) {
   
        RootContext.bind(xid); // 将本地事务加到分布式事务组中去
        return baseMapper.insertScoresGoodInfos(sysType, sysType + UUID.randomUUID().toString());
    }

maven

版本如下 seata 版本为1.6.1 (SpringCloud Alibaba里面自带的,如果想用更高版本的可以 排查单独引入 不推荐这个比较坑)


        <spring-cloud.version>2021.0.8</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
        <spring-boot.version>2.7.13</spring-boot.version>
        <druid.version>1.2.18</druid.version>
        <dynamic-ds.version>3.5.2</dynamic-ds.version>
        <mysql.version>5.1.49</mysql.version>



            <!-- SpringCloud 微服务 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- SpringCloud Alibaba 微服务 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- SpringBoot 依赖配置 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <!-- Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <!-- Dynamic DataSource -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
                <version>${dynamic-ds.version}</version>
            </dependency>

        <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            
		<!-- Seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>


相关推荐

  1. SpringCloud服务调用失败Seata无法解决办法

    2023-12-27 09:10:02       33 阅读
  2. springboot数据库失败原因

    2023-12-27 09:10:02       34 阅读
  3. WordPress插件无法安装一直失败的原因和解决办法

    2023-12-27 09:10:02       35 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-27 09:10:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-27 09:10:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-27 09:10:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-27 09:10:02       20 阅读

热门阅读

  1. 【常用前端框架总结】

    2023-12-27 09:10:02       37 阅读
  2. 产业互联网,并不存在所谓的平台和中心

    2023-12-27 09:10:02       43 阅读
  3. AutoSAR(基础入门篇)3.1-Autosar中RTE的概述

    2023-12-27 09:10:02       35 阅读
  4. Pillow库画图用法记录python

    2023-12-27 09:10:02       39 阅读
  5. LeetCode453. Minimum Moves to Equal Array Elements

    2023-12-27 09:10:02       32 阅读
  6. C语言中的结构体和联合体:异同及应用

    2023-12-27 09:10:02       37 阅读
  7. Go语言入门:Go程序的基础结构

    2023-12-27 09:10:02       27 阅读
  8. C++入门【16-C++ 从函数返回数组】

    2023-12-27 09:10:02       33 阅读