前言
幂等和重复支付,是两个不同的问题,必须得分开,不能混淆,才能理解清楚。
下面以扫码支付为例。
幂等
幂等的解决方案是:先查后改 + 锁。
先查后改
直接举例,第一次支付请求,订单号1并且支付成功。
然后,第二次请求,但是是同一笔订单,即同一个订单号。
那怎么办?
这个时候,会先查询,即根据订单号1从数据库查询订单,并且会检查订单状态是否已经支付成功,如果成功,就直接拒绝第二次请求,为什么要拒绝?因为不同的请求线程,本质是两个事务,所以这两个事务不能出现篡改同一笔订单数据的问题。这个就是幂等。
幂等的本质,针对的是同一笔订单,然后要解决同一笔订单的不同请求事务的篡改数据的问题。
锁
先查后改,可以解决99%的问题。说白了,就是,如果是非高并发,其实先查后改就够了。
但是,高并发的情况,就有可能篡改数据。哪怕已经先查后改,还是会出现篡改数据的问题。这个就是两个事务,会出现篡改数据的情况。
所以,怎么解决?加锁。分布式系统,就加分布式锁,比如redis分布式锁。
小结
所以,最终的方案就是,一锁二查三改。
一锁二查三改的代码写在哪里?交易服务。
重复支付
重复支付是多次支付,就是本来买100块钱的东西,结果你支付了两次。
多次支付的具体场景是这样,第一次扫码,然后进入输入金额页面,第二次再提交支付。第二次请求才是真正支付,说白了,就是支付的时候,不小心多次点击提交支付按钮。
一般情况下,前端会按钮置灰,并且还需要输入支付密码,所以其实实际上是很少发生多次支付的。
但是为了以防万一,还是得需要在后端控制一下,怎么控制?基于token机制。具体流程是,第一次扫码,后端写token/订单(包含订单id字段)到redis缓存,并且会返回给前端页面,第二次请求即提交支付的时候,token会再次带到后端来,然后从缓存取,所以哪怕多次提交,最终获取的还是同一笔订单,这里的话就把多次支付的问题给控制住了。
再结合前面讲的同一笔订单,如果出现幂等问题,那么就是用一锁二查三改这套方案来解决。
token/订单的代码写在哪里?网关入口。
所以,核心流程是:扫码——》网关入口:解决重复支付问题——》交易服务:解决幂等问题。
说白了,就是二者结合,才最终解决幂等问题和重复支付这两个不同的问题。