【问题】如何避免并发情况下的重复提交
2018-02-06 18:55
246 查看
背景
在业务开发中,我们常会面对防止重复请求的问题。当服务端对于请求的响应涉及数据的修改,或状态的变更时,可能会造成极大的危害。重复请求的后果在交易系统、售后维权,以及支付系统中尤其严重。重复请求的一致性问题又称幂等性问题。
背景
唯一键法
订单状态法
基于缓存的数据验证
利用数据库的主键唯一
缓存计数器
先弄清楚啥叫幂等性。
比如
1. 一个用户把他的性别设置为男,无论他设置多少次,他的性别都是男。
2. 比如我们查询余额(假设并没有任何使余额发生变化的行为),那么我们点击多少次查询余额得到的结果都应该是一样的。
以上都是幂等的。
但是,如果我们进行一笔交易,这笔交易实际已经正常的插入了数据库,但由于前台操作的抖动,快速操作,网络通信或者后端响应慢等原因,又来了一次。导致用户平白无故支付了两次。 这种情况我们该如何避免呢??
首先前端优化是必不可少的,这里暂且不谈。。。
我们谈谈后端
唯一键法
并发并不意味着每个request都处理的很快,也不意味着机器之间就不共享数据了。可以把所有带有副作用的task都给一个GUID,最后写进数据库之前查询一下这个GUID是否已经被执行过了。订单状态法
用户调用支付,扣款成功后,更新对应订单状态,然后再保存流水。(支付状态:未支付,已支付)
步骤:
1、查询订单支付状态
2、如果已经支付,直接返回结果
3、如果未支付,则支付扣款并且保存流水
4、返回支付结果
理论上,只要在数据状态更新前完成了查询操作,则业务逻辑的重复处理就依旧会发生。
基于缓存的数据验证
Redis存储查询轻量快速。在request进来的时候,可以先记录在缓存中。后续进来的request每次进行验证。整个流程处理完成,清除缓存。I. 每次交易发起申请,读取缓存中是否有以orderId为key的值 II. 没有,则往缓存中写入以orderId为key的value III.有,则说明有该订单正在进行。 IV. 操作完清缓存,或者缓存存值的时候设置生命周期
利用数据库的主键唯一
同一笔订单进来的话,数据库会报唯一索引的错误。这个时候后台对这个异常进行处理并返回给前端提示。(那么如何保证误操作的交易的订单号都是一个订单号呢,如何和正常的多次交易情况区分开?)
缓存计数器
由于数据库的操作比较消耗性能,了解到redis的计数器也是原子性操作。果断采用计数器。既可以提高性能,还不用存储,而且能提升qps的峰值。还是以支付为例子:
每次request进来则新建一个以orderId为key的计数器,然后+1。
如果>1(不能获得锁): 说明有操作在进行,删除。
如果=1(获得锁): 可以操作。
操作结束(删除锁):删除这个计数器。
相关文章推荐
- 【CSDN常见问题解答】如何避免表单重复提交
- 室友碰到的小问题随机排列如何避免重复
- 数据库并发插入避免重复数据的问题
- 如何避免因jsp刷新而重复提交数据
- MVC中如何避免POST请求中出现的重复提交
- 交易系统使用storm,在消息高可靠情况下,如何避免消息重复
- 如何避免重复提交
- 高并发带来的重复提交问题解决方案
- 网络充值支付过程游戏公司如何防止由于页面多次刷新导致重复提交数据导致多次充值的问题
- 解决java读取大文件内存溢出问题、如何在不重复读取与不耗尽内存的情况下处理大文件
- 网页刷新的问题。避免数据重复提交。
- 并发insert情况下会发生重复的数据插入问题
- 并发insert情况下会发生重复的数据插入问题
- 解决java读取大文件内存溢出问题、如何在不重复读取与不耗尽内存的情况下处理大文件
- 网页中超链接的简化问题(如何避免超链接的get提交)
- jsp或struts如何避免Form重复提交,不然数据中的插入的纪录有重复的!
- jsp或struts如何避免Form重复提交,不然数据中的插入的纪录有重复的!
- 在JSP中动态生成随机验证码,登录时后台校验验证码,以及如何避免同一个验证码被重复提交爆破密码
- 如何避免mysql 主从同步中由于数据记录找不到和主键重复错误导致的同步异常问题
- ASP.NET AJAX FORM 如何避免重复提交?