1.总结软件系统上线后,最近在检查项目数据库的时候,发现有些表有很多重复的数据。对于此类脏数据,初步分析可能有以下可能来源:1、由于用户误操作,表单提交按钮被多次点击2、由于网速等原因,导致页面卡顿,用户反复刷新提交页面3.黑客或恶意用户使用postman等网络工具恶意重复提交表单。这些情况都有可能会导致表格重复提交,数据重复,比如订单表格。重复提交订单数据带来的问题,不仅会造成数据混乱,还会造成业务混乱。那么问题来了,我们如何防止用户重复提交数据呢?程序实践如下!2、方案实践下面以防止重复提交订单为例,介绍最简单、成本最低的方案。我们先来看一张图,就是这个方案的核心流程图。实现逻辑如下:1、当用户进入订单提交界面时,调用后台获取请求的唯一ID,并将唯一ID值埋入页面中。2、当用户点击提交按钮后,后台检查唯一ID是否被使用过,如果没有,继续后续逻辑;如果已经使用,会提示重复提交从数据库层面防止重复提交的总体思路如上,实际代码如下!2.1.为数据库表添加唯一键约束以order表为例,添加一个request_id字段,并设置为唯一约束。结构如下:CREATETABLEtb_order(idbigint(20)unsignedNOTNULL,order_novarchar(100)NOTNULL,....request_idvarchar(36)NOTNULL,PRIMARYKEY(id),UNIQUEKEYuniq_request_id(request_id)使用BTREE)引擎=InnoDB默认字符集=utf8mb4;2.2编写获取请求唯一ID的接口@RestController@RequestMapping("api")publicclassCommonController{/***获取getRequestId*@return*/@RequestMapping("getRequestId")publicResResultgetRequestId(){Stringuuid=UUID.randomUUID().toString();返回ResResult.getSuccess(uuid);}}2.3。提交业务时勾选唯一ID@RestController@RequestMapping("order")publicclassOrderController{@AutowiredprivateOrderServiceorderService;/***订单*@paramrequest*@return*/@PostMapping(value="order/confirm")publicResResultconfirm(@RequestBodyOrderConfirmRequestrequest){//调用订单相关逻辑if(StringUtils.isEmpty(request.getRequestId())){returnResResult.getSysError("请求ID不能为空!");}if(request.getRequestId().length()!=36){returnResResult.getSysError("请求ID格式错误!");}//检查当前Request一个唯一ID,是否已经存在,如果存在,则重新提交Ordersource=orderService.queryByRequestId(request.getRequestId());if(Objects.nonNull(source)){returnResResult.getSysError("当前订单已提交成功,请勿重复提交");}orderService.confirm(请求);返回ResResult.getSuccess();如果是并发请求不用担心,因为数据库表设置了唯一索引,特别是只有一个有效数据才会插入成功,可以防止产生重复数据3.小结对于低阶流量的系统,可以采用这种请求唯一ID+对数据表添加唯一索引约束的方式,防止接口重复提交!虽然简单粗暴,但是非常有效!可能有人会问,看上面代码生成唯一请求ID很简单,为什么不直接在前端生成唯一请求ID,然后提交呢?之所以把获取请求唯一ID的生成规则放在后端,是因为生成规则可以自己定义,不需要用uuid来生成。也可以使用雪花算法,或者自己设计一套计算规则,保证当前业务提交时的请求ID唯一。比如预先生成一个唯一的订单号作为请求的唯一ID,然后提交。规则在后台生成,会更加灵活!
