经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
如何防止用户重复提交订单?(上)
来源:cnblogs  作者:程序员志哥  时间:2022/11/23 18:51:50  对本文有异议

一、摘要

对于投入运营的软件系统,最近小编在巡检项目数据库的时候,发现某些表存在不少的重复数据,对于这样的脏数据,初步分析大致的来源有以下可能:

  • 1.由于用户误操作,多次点击表单提交按钮
  • 2.由于网速等原因造成页面卡顿,用户重复刷新提交页面
  • 3.黑客或恶意用户使用 postman 等网络工具,重复恶意提交表单

这些情况都可能会导致表单重复提交,造成数据重复,比如订单表,重复提交订单数据所造成的问题,可能不仅仅是数据上的混乱,也会造成业务混乱。

那么问题来了,我们该如何防止用户重复提交数据呢?

方案实践如下!

二、方案实践

下面我们以防止重复提交订单为例,向大家介绍最简单的、成本最低的解决办法

我们先来看一张图,这张图就是本次方案的核心流程图。

实现的逻辑,流程如下:

  • 1.当用户进入订单提交界面的时候,调用后端获取请求唯一ID,并将唯一ID值埋点在页面里面
  • 2.当用户点击提交按钮时,后端检查这个唯一ID是否用过,如果没有用过,继续后续逻辑;如果用过,就提示重复提交
  • 3.最关键的一步操作,就是把这个唯一ID 存入业务表中,同时设置这个字段为唯一索引类型,从数据库层面做防止重复提交

防止重复提交的大体思路如上,实践代码如下!

2.1、给数据库表增加唯一键约束

以订单表为例,新增一个request_id字段,并设置为唯一约束,结构如下:

  1. CREATE TABLE tb_order (
  2. id bigint(20) unsigned NOT NULL,
  3. order_no varchar(100) NOT NULL,
  4. ....
  5. request_id varchar(36) NOT NULL,
  6. PRIMARY KEY (id),
  7. UNIQUE KEY uniq_request_id (request_id) USING BTREE
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2、编写获取请求唯一ID的接口

  1. @RestController
  2. @RequestMapping("api")
  3. public class CommonController {
  4. /**
  5. * 获取getRequestId
  6. * @return
  7. */
  8. @RequestMapping("getRequestId")
  9. public ResResult getRequestId(){
  10. String uuid = UUID.randomUUID().toString();
  11. return ResResult.getSuccess(uuid);
  12. }
  13. }

2.3、业务提交的时候,检查唯一ID

  1. @RestController
  2. @RequestMapping("order")
  3. public class OrderController {
  4. @Autowired
  5. private OrderService orderService;
  6. /**
  7. * 下单
  8. * @param request
  9. * @return
  10. */
  11. @PostMapping(value = "order/confirm")
  12. public ResResult confirm(@RequestBody OrderConfirmRequest request){
  13. //调用订单下单相关逻辑
  14. if(StringUtils.isEmpty(request.getRequestId())){
  15. return ResResult.getSysError("请求ID不能为空!");
  16. }
  17. if(request.getRequestId().length() != 36){
  18. return ResResult.getSysError("请求ID格式错误!");
  19. }
  20. //检查当前请求唯一ID,是否已经存在,如果存在,再提交就是重复下单
  21. Order source = orderService.queryByRequestId(request.getRequestId());
  22. if(Objects.nonNull(source)){
  23. return ResResult.getSysError("当前订单已经提交成功,请勿重复提交");
  24. }
  25. orderService.confirm(request);
  26. return ResResult.getSuccess();
  27. }
  28. }

如果是并发请求也不用担心,因为数据库表已经设置了唯一索引,尤其只有一条有效数据会插入成功,可以防止重复的数据产生

三、小结

对于下单流量不算高的系统,可以采用这种请求唯一ID+数据表增加唯一索引约束的方式,来防止接口重复提交

虽然简单粗暴,但是十分有效

可能有的人会问,看上面的代码生成请求唯一 ID 很简单,为啥不直接前端生成一个请求唯一ID,然后提交呢?

之所以把获取请求唯一ID的生成规则放在后端,好处就是生成规则可以自己定义,也并不一定要用uuid来生成,也可以用雪花算法,或者自己设计一套计算规则,保证当前业务提交时请求ID是唯一的,比如事先生成唯一的订单号,作为请求唯一ID,然后再提交,规则放在后端来生成,会更加灵活!

原文链接:https://www.cnblogs.com/dxflqm/p/16914651.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号