【不靠谱程序员】订单付款成功后,不是先改状态,而是...
做过税地系统或三方支付或对接过银行支付通道的朋友应该清楚,我们的支付系统在调用银行通道获取到付款单的终态后,涉及到记账、结算、通知下游商户等业务逻辑。这其中,有一项默认的操作是,更新付款单的状态。
并且,应该先变更状态,变更状态成功后,然后再去执行其他业务逻辑。
我们在参与一次代码评审时,就发现了不靠谱的事情。开发人员先发起异步记账,然后才是更新付款单状态。
/** * 订单完成的业务逻辑封装 * @param paymentOrder 付款单对象 * @param payResult 付款结果 */ void handlePaymentCompletion(PaymentOrder paymentOrder, PaymentResult payResult){ if (PaymentOrderStatusEnum.isFinalState(payResult.getStatus())){ return; } // 订单完成,异步记账 accounting(paymentOrder); // 持久化更新订单付款状态 updateOrderPayResult(paymentOrder, payResult); // 异步通知下游商户系统 notifyMerchant(paymentOrder); }
那么,这会出现什么后果呢?
假如持久化记账完成了,商户的账户余额也变更了,但是,变更付款单状态时,由于字段超长等某些原因导致异常,程序中断,付款单状态未能持久化变更,也就是说,此时数据库里付款单的状态依然是“付款中”。那么,定时查单任务(或查单延迟消息队列)在下一次调度时还会读取到这一笔“付款中”的交易,然后继续查询银行通道,通道返回终态后,又开始执行记账逻辑,这为重复记账埋下了种子。
重复记账会产生什么后果呢?
①如果付款单是付款失败,商户账户可用余额会增加。重复记账,就会出现余额异常翻倍增加,意味着商户可以用增加的这笔“意外之财”继续付款。这是资金风险的原罪。
②如果付款单是付款成功,商户账户可用余额减少。重复记账,就会导致商户余额异常成倍减少,意味着商户无法继续付款。我(商户)明明给你充钱了,你却告诉我余额不足,不让我用,我投诉你!
因此,这个顺序颠倒的代码逻辑是不是很可怕?支付系统最怕这种资金风险。上面说的定时任务只是一方面,回调或并发场景下也同样会导致这个资金隐患。
借助这个案例,来强调一下,业务处理流程的先后顺序是很重要的,一定要摸索清楚。日常开发中养成严谨的好习惯,关键时刻才能彰显靠谱。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/17773278.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体
2016-10-18 MySql.Data.MySqlClient.MySqlException: Parameter ‘@maxid’ must be defined