文章

【若依】7、处理幂等性的思路与防止表单重复提交

处理幂等性的常见思路

Token 机制:

😖没有理解😖

  1. 首先客户端请求服务端,获取一个 token,每一次请求都获取到一个全新的 token(当然这个 token 会有一个超时时间),将 token 存入 redis 中,然后将 token 返回给客户端;
  2. 客户端将来携带刚刚返回的 token 去请求一个接口;
  3. 服务端收到请求后,分为两种情况:
    1. 如果 token 在 redis 中,直接删除该 token,然后继续处理业务请求;
    2. 如果 token 不在 redis 中,说明 token 过期或者当前业务已经执行过了,那么此时就不执行业务逻辑;
  4. 优势:实现简单;
  5. 劣势:多了一个获取 token 的过程;

    去重表:(主要是利用 MySQL 的唯一索引机制来实现的)

  6. 客户端请求服务端,服务端将这次的请求信息(请求地址、参数。。。)存入到一个 MySQL 去重表中,这个去重表要根据这次请求的某个特殊字段建立唯一索引或者主键索引;
  7. 判断是否插入成功:
    1. 成功:继续完成业务功能;
    2. 失败:表示业务已经执行过了,这次就不执行业务了;
  8. 存在的问题:MySQL 的容错性会影响业务、高并发环境可能效率低;

    Redis 的 setnx :

  9. 客户端请求服务端,服务端将能代表本次请求唯一性的业务字段,通过 setnx 的方式存入 redis,并设置超时时间;
  10. 判断 setnx 是否成功:
    1. 成功:继续处理业务;
    2. 失败:表示业务已经执行过了;

      设置状态字段:

      要处理的数据,有一个状态字段; 判断状态字段;

      锁机制:

  11. 乐观锁:数据库中增加版本号字段,每次更新都根据版本号来判断;更新之前先去查询要更新记录的版本号,更新的时候,将版本号也作为查询条件;
    1
    2
    
    select version from xxx where id=xxx;
    update xxx set xxx=xxx where xx=xx and version=xxx;
    
  12. 悲观锁: 假设每一次拿数据都会被修改,所以直接上排他锁就行了;
    1
    2
    3
    4
    
    start;
    select*from xxx where xxx for update;
    update xxx;
    commit;
    

    防止表单重复提交

    思路:拦截器中将请求信息(Token、地址,参数。。。)存到 Redis 中(当然需设置一个过期时间),处理业务前与 Redis 中的请求信息做比较;

    解决存在的问题

    存在的问题: request.getParameter()可以反复获取是没有问题的; 如果请求参数是JSON格式的,通过IO流获取request.getReader().readLine(),就会出现问题; 因为在请求拦截的时候,就已经获取过了,处理业务的时候就获取不到了; image.png 解决问题的思路:用装饰器模式来处理HttpServletRequest; 😖小困惑😖 image.png

源码

yueyazhui/ruoyi_repeat_submit

本文由作者按照 CC BY 4.0 进行授权