如何避免重复提交问题

参考:如何避免重复提交问题 - 简书

“避免重复提交”,总结下大致有以下两个方向:

  1. 真正做到不重复提交
  2. 即使重复提交,也能够使最终的结果和单次提交的结果保持一致。也就是所谓的“幂等性”。

幂等性

所谓幂等性,就是一个接口,多次发起同一个请求,该接口得保证结果是准确的,比如不能多扣款、不能多插入一条数据、不能将统计值多统计 1,这就是幂等性。

产生原因(基于浏览器分析):

  1. 多次点击页面提交按钮
  2. 点击刷新页面
  3. 使用浏览器后退按钮重复之前的操作,导致重复提交表单
  4. 使用浏览器历史记录重复提交表单
  5. 浏览器重发http请求
  6. nginx重发...

场景举例:

        例如,某分布式交易服务提供的付款接口,由于前端未知操作(或者由于网络超时导致的超时重试)导致对一笔订单发起了两次支付请求,且分别请求到不同服务器上,结果造成一笔订单扣款两回。

问题解析 → 保证幂等性:

  1. 对于每个交易请求都对应一个唯一标识符。比如:订单业务中的“唯一订单号”(对订单号建立mysql的唯一索引),每个订单号最多只能支付一次。
  2. 每次处理完交易请求后,都有一个记录标识这个请求状态为“已处理”。常见方案:数据库中插入一条订单记录,或者增加“交易状态”字段来表明是否交易成功。
  3. 每次收到交易请求,都先查询并判断之前是否已支付过。如果已支付,那么新插入的订单记录就会因为“mysql唯一键约束”而导致插入订单失败。若插入失败则表示可能先前存在记录,也就不会再重复扣款了。

如何避免重复提交:

  1. 利用MySQL的唯一索引,若重复insert订单数据会报错。update订单时,使用乐观锁(version比较法)
  2. 使用悲观锁(如mysql行锁 for update),对资源即订单记录上锁。但此方式并发性能较差,仅适用于请求量不大的单体应用。
  3. 通过redis设置标识位,用户在支付一个订单前,先插入一条交易记录到mysql。若插入成功,那么系统可以同时写一个交易成功标识的key到redis中(set order_id payed)。倘若下次来了重复请求,先尝试在缓存中查询key,若key已存在说明支付过了,这样就可以避免重复支付。


前端侧:

  1. 前端js提交禁止按钮:可以用一些js组件
  2. 重定向页面:当用户提交表单后,转到提交成功信息的页面,以避免用户F5导致的重复提交
  3. ...


总之,先查询订单记录是否存在,然后再判断是否执行 insert 操作!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值