开发小技巧系列文章,是本人对过往平台系统的设计开发及踩坑的记录与总结,给初入平台系统开发的开发人员提供参考与帮助。
重复生成数据,在实际的开发过程中是一个常见的问题,“重复生成订单”只是一个例子,从这个例子中,来说明怎么去防止出现这个问题,也给初入开发的人员提供参考。
怎么会出现这种问题呢?
情况1: 用户界面操作
用户在界面上连续点击多次“按钮”,由于网络或者后台处理时长的原因,浏览器对服务器发送多次HTTP请求,导致服务器接收到多次一模一样的数据,在数据库中生成多条一模一样的数据。
情况2: 后台接口对接/MQ消费
在做功能开发的过程,有时候需要跟其他业务系统进行对接,通过http或者MQ或者其他协议方式,来交互数据,由于网络或者其他原因(比如在MQ场景中,没有控制好锁),导致服务方多次执行同一份数据,生成一模一样的数据库记录。
“数据重复被处理”的问题,其实是数据幂等性的问题,可以使用幂等性的机制来解决,保证同一份数据的处理结果只有一个。那有什么解决办法呢?
方案一、前端处理
前端界面加loading/按钮置灰,即用户操作按钮过后,将操作过的按钮灰,不能连续点击,或者界面加上一个loading的效果,让用户进行等待。这是最普通的处理方式,能防住普通的用户,但是防不了通过接口调用(高级用户)。
方案二、预分配ID及加锁
预分配ID,在下单的场景中,可以预先分配一个ID(ID可由后台生成,或者前端生成),后台在处理数据时,对同一个ID,只处理一次,多次提交后台时,返回特殊状态码给前端(表示“操作在进行中,不要重复提交”),可以采用redis的锁来控制“预分配ID”。
方案三、数据唯一主键法
数据表唯一主键法,也是在数据提交前,预分配一个唯一的ID,或者拿业务的ID(如订单号),在消息的场景中,可以使用MQ的messageId。然后在数据库中新建一张表,用来存储收到的数据/消息,将预分配的ID设置为“唯一主键”, 只有当数据写入成功后,在执行业务处理,如果写失败,则返回不处理(重复数据/消息),这个场景在之前做商城时使用过,通过订单的消息来做各个维度的统计(前期未考虑到大量的消息的情况下,没有很好分配好锁的机制)。
这个方式适用于其他数据一致性的场景上,订单重复只是其中之一。
如果读者有更好的方法,可以回复。