Archi - 幂等问题
1. 什么是幂等问题?
就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了了副作用。
举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣了钱,流水记录也变成了两条。
2. 怎么保证幂等性?
2.1 通过代码逻辑判断实现
通过代码逻辑判断实现接口幂等性,只能针对一些满足判断的逻辑实现,具有一定局限性。
原始版本
boolean pay(int accountid,BigDecimal amount) //用于付款,扣除用户的
这种情况下,支付系统已经扣款,但是订单系统因为网络原因,没有获取到确切的结果,因此订单系统需要重试。由上图可见,支付系统并没有做到接口的幂等性,订单系统第一次调用和第二次调用,用户分别被扣了两次钱,不符合幂等性原则(同一个订单,无论是调用了多少次,用户都只会扣款一次)。如果需要支持幂等性,付款接口需要修改为以下接口:
幂等版本
boolean pay(int orderId,int accountId,BigDecimal amount)
通过orderId来标定订单的唯一性,付款系统只要检测到订单已经支付过,则第二次调用不会扣款而会直接返回结果
2.2 使用token机制实现
使用token机制实现接口幂等性,通用性强的实现方法。
token机制实现步骤:
- 生成全局唯一的token,token放到redis或jvm内存,token会在页面跳转时获取.存放到pageScope中,支付请求提交先获取token
- 提交后后台校验token,执行提交逻辑,提交成功同时删除token,生成新的token更新redis ,这样当第一次提交后token更新了,页面再次提交携带的token是已删除的token后台验证会失败不让提交
token特点: 要申请,一次有效性,可以限流
注意: redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用
2.3 分布式锁