全局异常处理Seata事务失效解决方案

2023-11-08

全局异常处理Seata事务失效解决方案

​ 最近的项目用到了seata来管理全局事务,在进行测试的时候,发现当service A 调用Service B时,如果ServiceA报错,ServiceB能回滚,但是如果ServiceB报错,ServiceA是无法进行回滚的。

​ 经过查找,发现是因为当时为了系统能统一处理全局异常,返回统一的异常信息给前端做了一个全局异常拦截,具体代码如下

/**
 * Controller统一异常处理
 *
 * @author : 777666
 * @date : 2022/01/19
 */
@ControllerAdvice
public class AllControllerAdvice {
    private static Logger logger = LoggerFactory.getLogger(AllControllerAdvice.class);

    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    }

    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     */
    @ModelAttribute
    public void addAttributes(Model model) {
    }


    /**
     * 捕捉BusinessException自定义抛出的异常
     *
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResultData handleBusinessException(BusinessException e) {
        String message = e.getMessage();
        if (message.indexOf(":--:") > 0) {
            String[] split = message.split(":--:");
            return ResultData.error(split[0], split[1]);
        }
        return ResultData.error(CodeEnum.DATA_ERROR.getCode(), message, null);
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public ResultData handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        logger.info("参数错误:" + e.getMessage());
        return ResultData.error(CodeEnum.PARAM_ERROR.getCode(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        logger.info("参数错误:" + e.getMessage());
        return ResultData.error(CodeEnum.PARAM_ERROR.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage(), null);
    }

    /**
     * 全局异常捕捉处理
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultData<String> errorHandler(Exception ex) {
        logger.error("接口出现严重异常:{}", ex.getMessage());
        return ResultData.error(CodeEnum.ERROR.getMsg());
    }

}

这么做的一个好处就是,无论你代码里面报了什么异常,我这个AOP都可以拦截到,并且返回给前端一个约定的值,而不会说返回给前端一串英文异常信息。

那么在使用seata的时候,如果这么做会有什么问题呢?

我们使用ServiceA调用ServiceB,此时让ServiceB 抛出一个异常,会发现一个现象,ServiceB回滚了,ServiceA没回滚,那么此时可以说分布式事务失效了。

经过查阅资料发现,如果异常被我们内部处理了(我们自定义的全局异常AOP拦截了),seata不会再处理这个异常信息,导致ServiceA的事务回滚失败

明白了这个,问题就比较好解决了

要么进行手动回滚,要么让所有分布式事务请求的接口不被这个AOP拦截不就可以了吗

针对AOP的处理,seata官方有一个解决方案

在这里,我们不用这个方式

首先,我们看下@ControllerAdvice这个注解

在这里插入图片描述

在这个注解中有一个basePackages的属性,也就是说,如果配置了这个属性,将只会拦截basePackages指定的包下面发生的异常

所以,我们只需要指定basePackages的值,再把远程调用的所有服务抽出来,关键代码如下

全局异常拦截器只需要处理正常controller下的所有请求

在这里插入图片描述

此时远程调用的包结构如下

在这里插入图片描述

此时再试一下,在ServiceB抛出一个除零异常
在这里插入图片描述

ServiceA此时感知到后,进行Rollback

在这里插入图片描述

说一说这种方式的局限性

在ServiceA和ServiceB都配置了全局异常的前提下,ServiceA去调用ServiceB

​ 如果ServiceA排除了远程调用的feign远程包,ServiceB没排除,那么ServiceB的分布式异常将被内部自己处理,seata不再处理,所以ServiceA不会回滚。

有一点就是,无论ServiceA、ServiceB是否排除feign远程包,只要作为调用方的ServiceA出现异常,作为被调用方ServiceB的事务都将发生回滚(由于对seata的内部原理还不是很清楚,具体情况需要后续研究了才明白)。

总结:在使用了seata管理分布式事务的情况下,如果项目内部使用了全局异常处理,需要把远程调用的包排除出去,否则可能会导致分布式事务失效

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

全局异常处理Seata事务失效解决方案 的相关文章

随机推荐

  • 【Qt-11】http通信(Get同步收发)

    Qt 9 HTTP请求 post方式 WXG1011的博客 CSDN博客 QT 6 QWebApp服务器搭建及使用 qtwebapp WXG1011的博客 CSDN博客 写在前面 在上面两篇博文的基础上 继续迭代功能 上面两篇博客已实现QW
  • 谈Delphi编程中资源文件的应用

    一 初级应用篇 资源文件一般为扩展名为res的文件 在VC中资源文件用得非常普遍 但Delphi在其联机帮助中对资源文件没作什么介绍 其实利用其自带的资源编译工具BRCC32 EXE 一般位于 Delphi BIN目录下 我们完全可以做出跟
  • StringBuilder和StringBuffer&String的区别,以及它的基本用法

    StringBuilder在java5中引入 算的上是一个StringBuffer的一个用于单线程的版本 StringBuilder用于拼接字符串 用法跟StringBuffer差不多 都是创建一个字符缓存区 不用像String一样每增加一
  • JVM Tenured space is exhausted

    使用Android Studio命令gradlew assembleRelease打包apk 遇到了JVM Tenured space is exhausted的错误 网上查询后原因是JVM分配内存不足 需要在项目下的grade prope
  • 期货和股票的区别在哪里

    期货和股票的区别在哪里 股票与期货有什么区别 1 概念不同 股票是股份公司发行的所有权凭证 是各个股东作为持股凭证的一种有价证券 而期货属于一种标准化可交易合约 一种到期必须执行的合约 2 交易场所不同 股票是需要在证券交易所进行交易的 例
  • Netty实战(一)Nett的概念及体系结构

    Nett的概念及体系结构 第一章 Java网络编程 1 1 Java NIO 1 2 选择器 第二章 Netty是什么 2 1 Netty简介 2 2 Netty的特性 2 2 1 设计 2 2 2 易于使用 2 2 3 性能 2 2 4
  • 读取文件最后N行

    转自 http www zuidaima com share 1550463669226496 htm 指定行数 可以获取到从这行到文件尾的所有行 分享自大熊 源文件 读取最后10行结果 代码下载地址 http www zuidaima c
  • C++的智能指针unique_ptr、shared_ptr和weak_ptr

    C 的智能指针是一种特殊的指针类型 它能够自动管理内存资源 避免常见的内存泄漏和多次释放等问题 C 11引入了三种主要的智能指针 unique ptr shared ptr和weak ptr 目录 unique ptr shared ptr
  • 双线性插值算法的详细总结

    原文出处 http blog csdn net xjz18298268521 article details 51220576 最近在做视频拼接的项目 里面用到了图像的单应性矩阵变换 在最后的图像重映射 由于目标图像的坐标是非整数的 所以需
  • pcie设备之驱动加载udev事件详解

    打卡打卡 udev 自内核2 6之后取代devfs udev配置 usr lib udev rules d etc udev rules d 如何触发udev事件 kobject uevent函数 pcie scan扫描函数 初始化pcie
  • python在linux系统下的编辑编译运行

    PYTHON在linux系统下的编辑编译 新建一个脚本文件 编写程序 运行程序 若安装了如spyder这样的编辑器 若是很简单的代码 新建一个脚本文件 gedit xxx py 新建py格式文件 编写程序 运行程序 在当前目录下 输入pyt
  • 【论文学习】FD-MonbileNet: IMPROVED MOBILENET WITH A FAST DOWNSAMPLING STRATEGY

    原文链接 https arxiv org abs 1802 03750 作者介绍了一种高效且在有限运算量限制上十分准确的网络 Fast Downsampling MobileNet FD MobileNet 其中心思想是在MobileNet
  • 中国钢铁产业产量分析与市场需求状况研究报告2022版

    中国钢铁产业产量分析与市场需求状况研究报告2022版 修订日期 2021年12月 搜索鸿晟信合研究院查看官网更多内容 第一章 产业转移的内涵及模式概述 1 1 产业转移的概念界定 1 1 1 产业转移的定义 1 1 2 产业转移的分类 1
  • mysql 连续打卡_MySQL查询连续打卡信息?

    最近多次看到用SQL查询连续打卡信息问题 自己也实践一波 抛开问题本身 也是对MySQL窗口函数和自定义变量用法的一种练习 01 建表 所用数据库为MySQL8 0 简单而不失一般性 建立一个仅有记录id 用户id 日期和打卡标记共4个字段
  • Python用户消费行为分析实例

    本文借鉴于知乎用户秦路的专栏https zhuanlan zhihu com p 27910430 这里只是自己理解基础上加以扩充和整理修改 丰富细节 由于手头用户消费数据的缺失我们这次采用专栏的数据进行实战 原数据在此 链接 https
  • vue判断input框不能为空_vue判断input输入内容全是空格的方法

    moduleinfo card count count phone 1 count 1 search count count phone 7 count 7 card des 支持文本 图片 视频 网站安全检测等多格式识别服务 提供色情 涉
  • 吃透MIPI接口,你必须了解它这三种PHY规范的区别

    MIPI接口及其物理层特性 MIPI 移动行业处理器接口 是专为移动设备 如智能手机 平板电脑 笔记本电脑和混合设备 设计的行业规范的标准定义 MIPI标准定义了三个通用的唯一物理 PHY 层 即MIPID PHY C PHY和M PHY
  • Stars in Your Window 【POJ - 2482】【线段树扫描线】

    题目链接 最开始的时候做成了贪心 离线求二维前缀和 然后树状数组维护二维偏序 这样的想法是存在BUG的 因为我是将每个点当成左下角 右下角 左上角 右上角来分别计算最大贡献的 但这样的做法却不是最贪心的 因为有可能该点并不作为矩形的四个顶角
  • [ESP][驱动]ST7701S RGB屏幕驱动

    ST7701SForESP ST7701S ESP系列驱动 基于ESP IDF5 0 ESP32S3编写 本库只负责SPI的配置 SPI设置屏幕信息两方面 由于RGB库和图形库的配置无法解耦 具体使用的图形库需要自行配置添加 本示例默认绑定
  • 全局异常处理Seata事务失效解决方案

    全局异常处理Seata事务失效解决方案 最近的项目用到了seata来管理全局事务 在进行测试的时候 发现当service A 调用Service B时 如果ServiceA报错 ServiceB能回滚 但是如果ServiceB报错 Serv