网站安全检测百度,免费大数据分析网站,wordpress自己做主题,企业网站怎么做中英文切换订单唯一性(防止重复下单)方案
重复下单产生原因#xff1a;
客户端原因#xff1a;
比如下单的按键在点按之后#xff0c;在没有收到服务器请求之前#xff0c;按键的状态没有设为已禁用状态#xff0c;还可以被按。又或者#xff0c;在触摸屏下#xff0c;用户手指…订单唯一性(防止重复下单)方案
重复下单产生原因
客户端原因
比如下单的按键在点按之后在没有收到服务器请求之前按键的状态没有设为已禁用状态还可以被按。又或者在触摸屏下用户手指的点按可能被手机操作系统识别为多次点击。
请求超时原因
用户的设备与服务器之间可能是不稳定的网络。这样一个下单请求过去返回不一定回得来。超时最大的问题是: 从用户的角度他无法确定下单的请求是还没到服务器还是已经到了服务器但是返回丢失了。——用户无法区分到底这个单下了还是没下。
用户各种无脑操作
心急的用户可能会重启流程/重启App/重启手机。在这种强制的手段下任何技术手段都会失效。 解决方案
方案一提交订单按钮置灰
防止用户提交最常规的做法就是客户端点击下单之后在收到服务端响应之前按钮置灰。
前端页面直接防止用户重复提交表单但网络错误会导致重传很多RPC框架、网关都有自动重试机制所以重复请求在前端侧无法完全避免。
当然这种方案也不是真的没有价值。
这种方案可以在高并发场景下从浏览器端去拦住一部分请求减少后端服务器的处理压力达到过滤流量的效果。
优点简单。基本可以防止重复点击提交按钮造成的重复提交问题。
缺点前进后退操作或者F5刷新页面等问题并不能得到解决。
方案二请求唯一ID数据库唯一索引约束
需要客户端在请求下单接口的时候需要生成一个唯一的请求号requestId服务端拿这个请求号判断是否重复请求。实现的逻辑流程如下 当用户进入订单提交界面的时候调用后端获取请求唯一ID并将唯一ID值埋点在页面里面。
当用户点击提交按钮时后端检查这个唯一ID是否用过如果没有用过继续后续逻辑如果用过就提示重复提交。
最关键的一步操作就是把这个唯一ID 存入业务表中同时设置这个字段为唯一索引类型从数据库层面做防止重复提交。 优点对于下单流量不算高的系统可以采用这种 请求唯一ID 数据表增加唯一索引约束的方式来防止接口重复提交
缺点并发量太低10wqps高并发 这个根本没法满足。 方案三reids分布式锁请求唯一ID
随着业务的快速增长每一秒的下单请求次数可能从几十上升到几百甚至几万。
面对这种下单流量越来越高的场景此时数据库的访问压力会急剧上升数据库会成为整个下单流程的瓶颈。
对于这样的场景我们可以选择引入缓存中间件来缓解数据库高并发场景下的压力实现的逻辑流程如下 当用户进入订单提交界面的时候调用后端获取请求唯一 ID同时后端将请求唯一ID存储到redis中再返回给前端前端将唯一 ID 值埋点在页面里面。
当用户点击提交按钮时后端检查这个请求唯一 ID 是否存在如果不存在提示错误信息如果存在继续后续检查流程。
使用redis的分布式锁服务对请求 ID 在限定的时间内进行加锁如果加锁成功继续后续流程如果加锁失败提示说明服务正在处理请勿重复提交。
最后一步如果加锁成功后需要将锁手动释放掉以免再次请求时提示同样的信息同时如果任务执行成功需要将redis中的请求唯一 ID 清理掉。 优点可以满足 10wqps高并发要求。
缺点每次提交订单的时候都需要调用服务端获取请求唯一ID 方案四redis分布式锁token:
创建订单的时候用订单信息计算一个哈希值去生成token 大致 流程如下
用户点击提交按钮服务端接受到请求后通过规则计算出本次请求唯一ID值
使用redis的分布式锁服务对请求 ID 在限定的时间内尝试进行加锁如果加锁成功继续后续流程如果加锁失败说明服务正在处理请勿重复提交。
最后一步如果加锁成功后需要将锁手动释放掉以免再次请求时提示同样的信息。 优点减少一次客户端与服务端之间的交互次数提高下单流程效率 用订单信息计算一个哈希值生成token /*** 提交订单*/PostMapping(/add)public Result add(RequestBody OrdersVO ordersVO) {StpUtil.checkRoleOr(admin, user);int hashKey ordersVO.hashCode();//获取tokenString key LOCK_KEY hashKey;//获取锁Boolean isLock redisTemplate.opsForValue().setIfAbsent(key, hashKey, 60, TimeUnit.SECONDS);if (!isLock) {//未获取到锁 说明订单重复提交 返回错误信息return Result.fail(ShopMsgConstant.REPEAT_SUBMIT.getCode(),ShopMsgConstant.REPEAT_SUBMIT.getMsg());}try {log.info(--------------获取锁成功生成订单------------------);return goodsOrderService.add(ordersVO);} finally {if (hashKey (int)redisTemplate.opsForValue().get(key) ){log.info(--------------释放锁------------------);redisTemplate.delete(key);}}} 方案五技术产品运营支持
如果经过上述方案处理还是会有用户误操作直到收到两份商品才发现下重了。
在实际设计中无论多么好的技术也不可能100%的拦截所有的可能性必须依靠**技术产品设计运营支持**的综合手段才能解决这类问题。
此时就得依靠运营/客服的支持了。 ****推荐使用方案四方案五