springcloud之seata在微服务模块全局异常捕捉后导致事务不滚优雅

peng_hui
发布于 2022-9-7 15:23
浏览
0收藏

作者 | IT学习道场

来源 | IT学习道场(ID:itlearndojo)

seata几个核心角色如下:事务协调者(TC) :管理全局的分支事务的状态,用于全局性事务的提交和

                                   回 滚。

事务管理者(TM) :用于开启、提交或回滚事务。

资源管理器(RM) :用于分支事务上的资源管理,向 TC 注册分支事务,上报

                                    分支事务的状态,接收 TC 的命令来提交或者回滚分支事务

异常捕获了,就相当你把事务try/catch了,seata的原理是入全局事务入口

(加了 @GlobalTransactional )方法,TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID,XID 在微服务调用链路的上下文中传播,在各自的微服务中RM会判断请求中是否有XID,有就开启一个分支事务

根据分支事务的情况,TM 向 TC 发起针对 XID 的全局提交或回滚决议,

TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

下面分析事务捕获,也就是说,分支事务没异常,则事务提交,不会回滚。

微服务中全局异常,会使得分支事务httpResponse中的status状态 = 200,TM就是认为事务是正常的,执行提交哦,

springcloud之seata在微服务模块全局异常捕捉后导致事务不滚优雅-鸿蒙开发者社区

这里解决方案就是在全局异常处理中,判断下是否开启了seata的全局事务,如果开启,则设置httpResponse中的status状态 = 500,这样TM就是认为事务是异常了,抛出TmTransactionException异常,事务就可以回滚了

解决方案代码

springcloud之seata在微服务模块全局异常捕捉后导致事务不滚优雅-鸿蒙开发者社区

这个是全局异常在一个方法中进行处理的

下面是大家习惯了的异常处理习惯,代码如下,原理都一样

/**
 * 描述: 全局异处理器 <br>
 * 时间: 2020-06-07 16:32  <br>
 * 作者:IT学习道场
 */
@ResponseBody
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler({Exception.class})
    public AjaxVo<?> handleException(Exception e, HttpServletResponse response) {
        //捕捉到的异常如果是自定义异常类,那么就返回自定义异常类中的错误码和错误信息
        String stackExceptionMsg = ExceptionUtil.stacktraceToString(e);
        //异常输出到日志
        log.error(stackExceptionMsg);
        setRespErrStatus(response);
        return AjaxVo.fail(message);
    }
    @ExceptionHandler({TokenException.class})
    public AjaxVo<?> handleTokenException(TokenException e, HttpServletResponse response) {
        setRespErrStatus(response);
        return AjaxVo.fail(e.getCode(), e.getMessage());
    }
    @ExceptionHandler({BaseException.class})
    public AjaxVo<?> handleBaseException(BaseException e, HttpServletResponse response) {
        setRespErrStatus(response);
        return AjaxVo.fail(e.getCode(), e.getMessage());
    }
    @ExceptionHandler({BindException.class})
    public AjaxVo<?> handleBindException(BindException e, HttpServletResponse response) {
        StringBuilder message = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        Iterator var4 = fieldErrors.iterator();
        while (var4.hasNext()) {
            FieldError error = (FieldError) var4.next();
            message.append(error.getField()).append(error.getDefaultMessage()).append(",");
        }
        message = new StringBuilder(message.substring(0, message.length() - 1));
        log.error(message.toString());
        setRespErrStatus(response);
        return AjaxVo.fail(message.toString());
    }
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public AjaxVo<?> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletResponse response) {
        StringBuilder message = new StringBuilder();
        Iterator var3 = e.getBindingResult().getFieldErrors().iterator();
        while (var3.hasNext()) {
            FieldError error = (FieldError) var3.next();
            message.append(error.getField()).append(error.getDefaultMessage()).append(",");
        }
        message = new StringBuilder(message.substring(0, message.length() - 1));
        log.error(message.toString());
        setRespErrStatus(response);
        return AjaxVo.fail(message.toString());
    }
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public AjaxVo<?> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e, HttpServletResponse response) {
        String message = "该方法不支持" + e.getMessage() + "媒体类型";
        log.error(message);
        setRespErrStatus(response);
        return AjaxVo.fail(message);
    }
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public AjaxVo<?> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletResponse response) {
        String message = "该方法不支持" + e.getMessage() + "请求方法";
        log.error(message);
        setRespErrStatus(response);
        return AjaxVo.fail(message);
    }
    @ExceptionHandler({IOException.class})
    public AjaxVo<?> handleIOException(IOException e, HttpServletResponse response) {
        log.error(ExceptionUtil.stacktraceToString(e));
        setRespErrStatus(response);
        return AjaxVo.fail(e.getMessage());
    }
    @ExceptionHandler({IllegalArgumentException.class})
    public AjaxVo<?> handleIllegalArgumentException(IllegalArgumentException e, HttpServletResponse response) {
        log.error(ExceptionUtil.stacktraceToString(e));
        setRespErrStatus(response);
        return AjaxVo.fail(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }
    @ExceptionHandler({NullPointerException.class})
    public AjaxVo<?> handleNullPointerException(NullPointerException e, HttpServletResponse response) {
        log.error(ExceptionUtil.stacktraceToString(e));
        setRespErrStatus(response);
        return AjaxVo.fail(HttpStatus.BAD_REQUEST.value(), MscmExceptionEnum.NULL_POINT_EXCEPTION.getMessage());
    }
    @ExceptionHandler({BusinessException.class})
    public AjaxVo<?> handleBusinessException(BusinessException e, HttpServletResponse response) {
        log.error(ExceptionUtil.stacktraceToString(e));
        setRespErrStatus(response);
        return AjaxVo.fail(HttpStatus.NOT_ACCEPTABLE.value(), e.getMessage());
    }
    @ExceptionHandler({ServiceException.class})
    public AjaxVo<?> handleServiceException(ServiceException e, HttpServletResponse response) {
        log.error(ExceptionUtil.stacktraceToString(e));
        setRespErrStatus(response);
        Result<Object> result = e.getResult();
        if (Objects.nonNull(result)) {
            return AjaxVo.fail(result.getCode(), e.getMessage());
        }
        return AjaxVo.fail(e.getMessage());
    }
  /**
   * 如果开启分布式事务,就设置response.status = 500,seata的tm(事务管理器)
   * 就是感知到 TmTransactionException异常,发起事务回滚
   */
    private void setRespErrStatus(HttpServletResponse response){
        //如果开启分布式事务,设置错误状态码,让事务回滚
        if (StringUtils.isNotBlank(RootContext.getXID())) {
            response.setStatus(HttpCode.SERVER_ERROR.value());
        }else {
            response.setStatus(HttpCode.OK.value());
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.

AjaxVo 是我们系统的全局响应统一数据结构

你get了吗?

分类
已于2022-9-7 15:23:51修改
收藏
回复
举报


回复
    相关推荐