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