表单重复提交、以及重复消费的幂等性问题解决方案

发布时间:2022-05-23 14:23:18 作者:yexindonglai@163.com 阅读(1648)

什么是幂等性

幂等是一个数学上的概念,在软件行业里指的是多次相同的请求只会有一次修改,哪些情况下会导致幂等性问题呢?

  1. 消息队列,为了保证消息不丢失,会有重发机制,有重发就会有重复消费的问题;
  2. 微服务,服务之间的调用会有失败的情况,也会有重发机制,
  3. 表单重复提交,前端的提交按钮在短时间内连续点击多次,就会有多个相同的请求同时打到后端;

解决方案

1、分布式锁 + 唯一索引

索引可以是全局的唯一uuid,也可以是一个自增唯一的数字,

  1. 在处理业务逻辑时进行上锁操作,
  2. 先在表中查询这个唯一索引是否已存在,若已存在则表示该请求已处理过,不需要再次处理,
  3. 若唯一索引不存在,则表示该请求未被处理过,进行处理,
  4. 处理完成后保存这个唯一索引到表中,证明这个请求是已被处理过的,
  5. 解锁

2、token机制(防止重复提交)

原理上通过session token来实现的(也可以通过redis来实现)。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。
下次客户端提交请求时,Token会随着表单一起提交到服务器端。

服务器端第一次验证相同过后,会将session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。

3、mysql 数据库的唯一索引

对于数据库插入类的场景,比如创建订单时,需要前端传入一个唯一的订单号,后端在存储这个订单号时肯定是加了唯一索引的,所以,在多次插入同一个订单时就会触发数据库的唯一约束异常;从而避免一次点击创建多次的问题。

4、redis set nx命令

redis的 set nx命令是保证了原子性的,只要有一个客户set key成功了之后,其他的客户端就不能在set这个key了,set nx可以解决mq的重复消费问题,在接收到mq的消息时,把这个消息通过set nx写入到redis里面,一旦这个消息被消费过,就不会被再次消费

5、状态机

状态机可以理解为是一个流程引擎,因为状态机的状态只会向前变更,所以,多次修改同一条数据的时候,一旦状态发生了改变,那么对这条数据修改造成的影响只会发生一次,这就是状态机的特性;

6、去重表

跟第一个(分布式锁 + 唯一索引)的方式类似,将已处理过的请求存储到一个表中,下次在处理时先查询这个表,判断是否已经处理过,若已经处理过,则不在处理

7、乐观锁

乐观锁——乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。乐观锁的实现方式多种多样可以通过version或者其他状态条件。

关键字后端