幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品使用约支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...
方法一、单次支付请求,也就是直接支付了,不需要额外的数据库操作了,这个时候发起异步请求创建一个唯一的id,这个id只能使用一次就作废,具体步骤如下:
异步请求获取id
调用支付,传入id
根据id查询此次操作是否存在,如果存在则表示该操作已经执行过,直接返回结果;如果不存在,支付扣款,保存
返回结果到客户端
如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的
方法二、分布式环境下各个服务相互调用
这边就要举例我们的系统了,我们支付的时候先要扣款,然后更新订单,这个地方就涉及到了订单服务以及支付服务了。
用户调用支付,扣款成功后,更新对应订单状态,然后再保存流水。
而在这个地方就没必要使用id了,因为会比较闲的麻烦
(支付状态:未支付,已支付)
步骤:
1、查询订单支付状态
2、如果已经支付,直接返回结果
3、如果未支付,则支付扣款并且保存流水
4、返回支付结果
如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的
对于做过支付的朋友,幂等,也可以称之为冲正,保证客户端与服务端的交易一致性,避免多次扣款。
另外如果针对一笔订单有多笔退款,则需要注意:
首先订单是已支付状态,转入退款。
然后,订单表上需要加已退款金额,退款中金额;
建立一张退款订单表保存退款的订单。
发起一笔退款在订单上:
update order set 退款中金额=#{退款 } , 已退款金额=已退款金额+#{退款} where id=#{订单号} and 退款中金额+已退款金额+本次退款金额 <= 订单金额的校验;
insert into refund () values ();
对每次发起退款的都校验 退款中金额+已退款金额+本次退款金额 <= 订单金额的校验。
对于高并发状态的时候需要加锁,每次进行一次退款操作。