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);//釋放鎖 }