如果一笔订单,用户在微信和支付宝同时支付,会怎么样?
如果一笔订单,用户在微信和支付宝同时支付,会怎么样?
回答重点
微信和支付宝都会支付成功,因为支付渠道是第三方系统,它们之间的数据是不相通的,因此无法阻止用户付款。

这样一来同一笔订单,用户就会多付了一笔钱,如何避免这个情况?
思路其实很清晰,不管是支付宝支付还是微信支付,用户支付后三方都会进行回调,这个回调处理逻辑在我们的系统中,因此我们可以在这里控制。
支付单都会有状态机,例如从支付中到支付成功,比如 update pay_info set status = "sucess" where payNo = '123' and status = "paying"
通过数据库对单一记录的更新加锁来保证先到的回调支付状态就能修改成功,后到的回调修改状态失败(因为wehre 条件不匹配,影响行数为 0 )。
针对影响行数为 0 的那次回调,我们就可以调用退款流程把用户多付的钱给退了。
假设微信支付回调执行成功,支付宝回调执行失败:

支付回调的幂等性处理
不过这里还有一个很关键的点需要注意,即支付回调的幂等性处理。
因为支付渠道回调我们后端服务,后端需要给对应的响应,不然支付渠道会重试回调,假设因为网络抖动或者其他因素导致支付渠道重复回调,必然会触发 SQL 执行失败,如果不做任何处理,肯定会触发退款流程了!那就玩完了,钱都退给用户,产生了资损。

这里的做法是需要在支付单中记录支付成功的渠道和对应的渠道支付单号,增加这部分的判断就能实现幂等,回调随便调,不会影响业务。
例如支付单增加:
pay_channel:支付渠道(如微信、支付宝等)transaction_id:渠道支付单号
流程如下:
1)判断支付单是否已完成支付
2)若已完成,则检查支付渠道和支付单号是否匹配。
- 若匹配,说明重复支付,直接返回
- 若不匹配,说是其他渠道,调用退款接口
3)若未完成,执行上述 update 逻辑,并将检查支付渠道和支付单号一并落库
4)如果 update 影响行数为 0 ,说明已经被其他渠道支付了,可以不返回响应,待三方支付再次回调,走上述的第二步逻辑(因为不确定是不是同渠道多次请求)。