单号幂等问题:主单包含多个子单场景

5 篇文章 0 订阅
1 篇文章 0 订阅

解决主单下多个子单,并会分开多次请求的场景下,主单号的幂等问题。

场景:

上游系统请求下游系统。

上游情况:

上游单据分为主单和子单(明细单),一个主单对应多个子单。

发送请求给下游系统的时候,参数结构是一个主单包含多个子单,并且可能会多次请求下游系统

下游情况:

下游单据同样分为主单和子单(明细单),一个主单对应多个子单。主单需要幂等。

上下游单据对应关系:

上游主单和下游主单是1:n关系。

上游子单和下游子单是1:1关系。

上游请求参数结构示例:

{
    "bizCode":"INVENTORY_ADJUST",
    "subOrderDTOs":[
        {
            "detailOrderId":"2000001394868005",
            "itemCode":"..."
        },
        {
            "detailOrderId":"2000001394868006",
            "itemCode":"..."
        }
    ],
    "locationCode":"TESTCS1",
    "mainOrderId":"CSCSTESTCS1kt210914000005",
    "merchantCode":"CSCS"
}

请求示例:

一个上游主单会拆分为多次请求:

第一次请求上游主单号CSCSTESTCS1kt210914000005,对应上游子单号2000001394868005和2000001394868006;

第二次请求上游主单号同样是CSCSTESTCS1kt210914000005,但是对应上游子单号是2000001394868007,2000001394868008和2000001394868009;

第三次有请求上游主单号同样是CSCSTESTCS1kt210914000005,但是对应上游子单号是,2000001394868008和2000001394868009;(子单号在第二次请求的时候已经包含在内了)

第四次有请求上游主单号同样是CSCSTESTCS1kt210914000005,但是对应上游子单号是,2000001394868009和2000001394868008;(与第三次子单号顺序不同)

第五次请求上游主单号CSCSTESTCS1kt210914000005,对应上游子单号2000001394868005和2000001394868006;(与第一次完全相同)

请求分析

对于前三次的请求,我们认为都是不需要幂等的。

因为子单号的信息不同,我们认为是不同请求。对于第三次的子单号在第二次请求的时候已经包含在内了,但是我们认为这是一次有效的请求,不需要进行幂等。

第四次和第五次请求是需要幂等的。因为子单号相同,顺序不同,认为是同一请求。

处理方案

主单号是一个字符串信息。

方案1

是用商家编码、仓编码、上游主单号、业务编码组成

"CSCS|TESTCS1|CSCSTESTCS1kt210914000005|INVENTORY_ADJUST"

存在问题:

同一主单不同子单,会被直接幂等掉,无法进行后续操作。

方案2

用商家编码、仓编码、上游主单号、子单号、业务编码组成

"CSCS|TESTCS1|CSCSTESTCS1kt210914000005|2000001394868005|2000001394868006|INVENTORY_ADJUST"

存在问题:

如果统一主单下有多个子单,如果子单过多的话,会导致组成的字符串过长,存入数据库时会出错。如果子单号排序不同,会被认为是不同单据。

方案3

用商家编码、仓编码、上游主单号、子单号排序后组成字符串再MD5加密、业务编码组成

"CSCS|TESTCS1|CSCSTESTCS1kt210914000005|2f7625f846b788abfd84b2e991dd03f8|INVENTORY_ADJUST"

优点:

同时解决了方案2和方案1的问题,保证了子单号的顺序,一次请求下子单过多,在经过MD5加密后可以得到固定长度的字符串,这样就可以满足主单据的幂等要求了。

伪代码

//获取子单号列表
List<String> outDetailOrderIdList  = getOutDetailOrderIdList(adjustOrderDTO);
//子单号列表排序
outDetailOrderIdList.sort(String::compareTo);
//子单号列表拼接字符串
String outDetailOrderIdListJoinStr = String.join("|", outDetailOrderIdList);
//子单号列表字符串进行MD5编码
String outDetailOrderIdListMd5 = MD5Util.toMD5(outDetailOrderIdListJoinStr);
        
//产生幂等号
String idempotentNoStr =  adjustOrderDTO.getMerchantCode() + VERTICAL_LINE + 
adjustOrderDTO.getWarehouseCode() + VERTICAL_LINE + 
adjustOrderDTO.getOutMainOrderId() +VERTICAL_LINE + 
outDetailOrderIdListMd5 + VERTICAL_LINE + 
adjustOrderDTO.getOutBizCode() + VERTICAL_LINE;
        

结论

所以我们采用了方案3来做幂等验证,刚好满足业务需求。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值