1、何为重复提交
重复提交是在第一次请求已经在进行处理或处理成功的情况下,人为的进行多次操作,导致不满足幂等要求的服务多次改变状态。
2、何为幂等
幂等是其任意多次执行所产生的影响均与一次执行的影响相同(不用担心重复执行会对系统造成改变)。
3、何时使用
场景一:在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交
场景二:表单提交后用户点击【刷新】按钮导致表单重复提交
场景三:用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交
4、造成影响
因为接口重复提交,会造成脏数据,进而导致数据被覆盖或有多笔业务数据问题。
5、实现思路
这里我们用到Redis的SET命令
set(key,value,"NX","EX",expireTime); //NX:表示如果key不存在,则设置key-value,否则返回null。 //EX:过期时间的单位/秒。
首先找到防止重复提交的标识信息,把参数组装好,这里可以使用MD5加密key,这样重复提交的请求生成的key就是一样的。请求前先获取锁,
请求结束后必须释放锁,同时我们设置锁的过期时间,可以有效防止死锁。
6、实现代码
//获取分布式锁 public synchronized boolean getRedisLock(String lockKey,String value,long expireTime){ String result=jedisCluster.set(lockKey,value,"NX","EX",expireTime);//单位秒 if("OK".equalsIgnoreCase(result)){ return true; }else{ return false; } } //释放分布式锁 public boolean releaseRedisLock(String lockKey,String value){ String script="if redis.call('get',KEYS[1])==ARGV[1] then redis.call('del',KEYS[1]) else return 0 end"; String result=jedisCluster.eval(script,Collections.singletonList(lockKey),Collections.singletonList(value)); if(1L==(Long)result){ return true; }else{ return false; } } //使用分布式锁 String key="xxx"; String value="xxx"; boolean lock=getRedisLock(key,value,2*60);//默认两分钟 try{ if(lock){ //数据保存逻辑 }else{ //重复提交提示 } } catch(Exception e){ }finally{ releaseRedisLock(key,value);//释放锁 }