项目中用到的分布式事务

2019/04/30 分布式

实际项目中用到的分布式事务

1.本地消息表+定时任务

  • 业务场景:

    创建完订单,进行支付,订单和支付属于不同的模块,需要用分布式事务进行处理。

  • 基本流程:

    支付模块相当于生产者,订单模块相当于消费者。支付模块中有一张异步通知表,订单模块有一张支付结果通知表。支付完成时,异步通知表增加一条数据,同时异步回调订单模块的支付通知接口,支付结果通知表中添加一条数据,并更新订单表相关的状态。如果回调失败,则进行重试,回调的接口必须满足幂等性。

    分布式事务-本地消息表

  • 具体流程:

    涉及到以下几张表的关键字段:

    payment表:

    列名 描述
    notify_url 支付结果异步通知url
    status 支付状态 0:等待支付,1:成功,2:失败

    payment_result表:

    列名 描述
    notify_status 结果通知状态 1:未通知,2:已成功通知

    notify_schedule表:

    列名 描述
    next_notify_time 下次通知时间
    notify_count 通知次数
    notify_status 通知状态 1:已通知,2:通知失败,3:通知成功
    notify_content 通知内容(异步通知订单模块接口的请求参数)

    order_payment_notify表:

    列名 描述
    status 支付结果 1:成功 10:失败

    order表:

    列名 描述
    order_status 订单状态 1:新增,2:已支付,3:处理中,4:已完成,5:已取消
    payment_status 支付状态 0:未支付,1:正在支付,2:支付完成。3:支付失败
    • 创建完订单,order_status=1,payment_status=0;

    • 支付模块进行支付,payment表中添加数据,支付成功后,payment表中status=1,payment_result表中添加数据,notify_status=1;

    • 准备通知订单模块更新数据,

      • notify_schedule表中添加数据,notify_status=1,
      • 异步回调订单模块的支付通知接口,
      • order_payment_notify表中添加数据,order表更新数据;

      如果通知成功,

      • 更新payment_result表中的数据,notify_status=2;
      • notify_schedule表中notify_status=3,
      • 订单模块中order_payment_notify表中status=1,
      • order表中order_status=2,payment_status=2;

      如果通知失败,通过定时任务进行重试,更新notify_schedule表中的数据。

  • 相关代码:

    • 支付模块:

      public boolean notifyResult() {
         //1.notify_schedule表中添加数据,notify_status=1
         notifyScheduleMapper.insertSelective(notify);
         //2.异步回调订单模块的支付通知接口
         JSONObject json = SoaHelper.postRequest(httpExcutor, message.getNotifyUrl(), jsonNotify, JSONObject.class, headers);
         //3.通知成功
         if(json != null){
            //payment_result表中添加数据
            paymentResultMapper.updateNotifyStatus(paymentId);
            //更新notify_schedule表中的数据,notify_status=3
            notifyScheduleMapper.updateByPrimaryKeySelective(notify);
         }else{
            //4.通知失败
            //更新notify_schedule表中的数据,notify_count+=1,更新next_notify_time,等待定时任务调用,再次执行
            //如果通知次数notify_count>9,设置为通知状态失败notify_status=2
            notifyScheduleMapper.updateByPrimaryKeySelective(notify);
         }
         return true;
      }sfsadfa
      
      public void notifyPendingResultJob() {
         //获取所有等待通知的记录:3天内,通知次数小于10,通知状态等于1
         List<NotifySchedule> lstNotify = getAllPendingResult();
         for(NotifySchedule notify : lstNotify){
            //调用上面的通知接口
            notifyResult();
         }
      }
      
    • 订单模块:

      public boolean onPaymentNotify(OrderPaymentNotify notify) {
         //1.同一支付结果的重复通知返回成功,保证幂等性
         if (orderPaymentService.isRepeatNotify(notify.getPlatformId(), notify.getPaymentCode())) {
            return true;
         }
         //2.order_payment_notify表添加记录,支付成功status=1
         orderPaymentService.addOrderPaymentNotify(notify);
         //3.更新order主表支付状态payment_status=2
         updatePaymentStatus(order, PaymentStatus.PS_PAY_COMPLETED.CODE, operator, DESC);
         //4.更新order主表订单主状态order_status=2
         updateOrderStatus(order, OrderStatus.OS_HAD_PAY.CODE, operator, DESC);
         //后续操作,生产券码,扣减库存等等
         ......
         return true;
      }
      

参考:

分布式事务-本地消息表实现方案

本地消息表

Search

    Table of Contents