簡單介紹redis分散式鎖解決表單重複提交的問題
導讀 |
在系統中,有些介面如果重複提交,可能會造成髒資料或者其他的嚴重的問題,所以我們一般會對與資料庫有互動的介面進行重複處理。本文就詳細的介紹一下redis分散式鎖解決表單重複提交,感興趣的可以瞭解一下
|
假如使用者的網速慢,使用者點選提交按鈕,卻因為網速慢,而沒有跳轉到新的頁面,這時的使用者會再次點選提交按鈕,舉個例子:使用者點選訂單頁面,當點選提交按鈕的時候,也許因為網速的原因,沒有跳轉到新的頁面,這時的使用者會再次點選提交按鈕,如果沒有經過處理的話,這時使用者就會生成兩份訂單,類似於這種場景都叫重複提交。
使用redis的setnx和getset
解決表單重複提交的問題。
1.引入redis依賴和aop依賴
org.springframework.bootspring-boot-starter-redis1.3.8.RELEASEorg.springframework.bootspring-boot-starter-aop
2.編寫加鎖和解鎖的方法。
/** * @author wangbin * @description redis分散式鎖 * @date 2019年09月20日 */ @Component public class RedisLock { private final Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowired private StringRedisTemplate redisTemplate; /** * @author wangbin * @description 進行加鎖的操作(該方法是單執行緒執行的) * @date 2019年09月20日 * @param key 某個方法請求url加上cookie中的使用者身份使用md5加密生成 * @param value 當前時間+過期時間(10秒) * @return true表示加鎖成功 false表示未獲取到鎖 */ public boolean lock(String key,String value){ //加鎖成功返回true if(redisTemplate.opsForValue().setIfAbsent(key,value,10, TimeUnit.SECONDS)){ return true; } String currentValue = redisTemplate.opsForValue().get(key); //加鎖失敗,再判斷是否由於解鎖失敗造成了死鎖的情況 if(StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){ //獲取上一個鎖的時間,並且重新設定鎖 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if(StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue)){ //設定成功,重新設定鎖是保證了單執行緒的執行 return true; } } return false; } /** * @author wangbin * @description 進行解鎖的操作 * @date 2019年09月20日 * @param key 某個方法請求url使用md5加密生成 * @param value 當前時間+過期時間 * @return */ public void unLock(String key,String value){ try { String currentValue = redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)){ redisTemplate.delete(key); } }catch (Exception e){ logger.error("redis分散式鎖,解鎖異常",e); } } /** * @author wangbin * @description 進行解鎖的操作 * @date 2019年09月20日 * @param key 某個方法請求url使用md5加密生成 * @return */ public void unLock(String key){ try { String currentValue = redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue)){ redisTemplate.delete(key); } }catch (Exception e){ logger.error("redis分散式鎖,解鎖異常",e); } } }
3.使用攔截器在請求之前進行加鎖的判斷。
@Configuration public class LoginInterceptor extends HandlerInterceptorAdapter { private final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); //超時時間設定為10秒 private static final int timeOut = 10000; @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisLock redisLock; /** * 在請求處理之前進行呼叫(Controller方法呼叫之前) * 基於URL實現的攔截器 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String path = request.getServletPath(); if (path.matches(Constants.NO_INTERCEPTOR_PATH)) { //不需要的攔截直接過 return true; } else { // 這寫你攔截需要乾的事兒,比如取快取,SESSION,許可權判斷等 //判斷是否是重複提交的請求 if(!redisLock.lock(DigestUtils.md5Hex(request.getRequestURI()+value),String.valueOf(System.currentTimeMillis()+timeOut))){ logger.info("===========獲取鎖失敗,該請求為重複提交請求"); return false; } return true; } } }
4.使用aop在後置通知中進行解鎖。
/** * @author wangbin * @description 使用redis分散式鎖解決表單重複提交的問題 * @date 2019年09月20日 */ @Aspect @Component public class RepeatedSubmit { @Autowired private RedisLock redisLock; //定義切點 @Pointcut("execution(public * com.kunluntop.logistics.controller..*.*(..))") public void pointcut(){ } //在方法執行完成後釋放鎖 @After("pointcut()") public void after(){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); redisLock.unLock(DigestUtils.md5Hex(request.getRequestURI()+ CookieUtils.getCookie(request,"userkey"))); } }
到此這篇關於redis分散式鎖解決表單重複提交的問題的文章就介紹到這了。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2845751/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java使用Redis實現分散式鎖來防止重複提交問題JavaRedis分散式
- redis分散式鎖的問題和解決Redis分散式
- 【Redis 分散式鎖】(1)一把簡單的“鎖”Redis分散式
- 如何避免表單的重複提交?
- jFinal避免表單重複提交
- PHP 防止表單重複提交PHP
- java 表單避免重複提交?Java
- 靈活運用分散式鎖解決資料重複插入問題分散式
- 分散式重複提交分散式
- redis實現分散式鎖---實操---問題解決Redis分散式
- form表單的簡單介紹ORM
- 分散式重複提交問題架構設計思路分散式架構
- Spring MVC表單防重複提交SpringMVC
- 簡單介紹Nginx tp3.2.3 404問題解決方案Nginx
- 簡單介紹redis加鎖常用幾種方式Redis
- 分散式鎖簡單入門以及三種實現方式介紹分散式
- RCmongodb出現id重複問題的簡單解決辦法jztMongoDB
- Struts2防止表單重複提交
- Spring Boot + Redis 解決陪玩平臺原始碼重複提交問題Spring BootRedis原始碼
- Redisson分散式鎖的簡單使用Redis分散式
- IW聊聊使用RedisTemplat實現簡單的分散式鎖的問題vawRedis分散式
- Redis 分散式鎖解決方案Redis分散式
- Redis分散式鎖解決方案Redis分散式
- PHP防止使用者重複提交表單PHP
- 如何解決表單提交的中文亂碼問題
- 基於Mongodb分散式鎖簡單實現,解決定時任務併發執行問題MongoDB分散式
- 用分散式鎖解決併發問題分散式
- C# Redis分散式鎖 - 單節點C#Redis分散式
- 分散式環境下利用快取解決重複性問題分散式快取
- java註解的簡單介紹Java
- JavaWeb——驗證碼功能解決表單重複提交問題(使用谷歌驗證碼jar包為例)JavaWeb谷歌JAR
- Redis應用(二) --分散式鎖以及壓測介紹Redis分散式
- springboot+redis分散式鎖-模擬搶單Spring BootRedis分散式
- PHP 實現簡單阻塞分散式鎖PHP分散式
- 使用redis分散式鎖解決併發執行緒資源共享問題Redis分散式執行緒
- 簡單介紹MySQL列印死鎖日誌的方法MySql
- 詳解Redis分散式鎖Redis分散式
- .NetCore使用Redis,StackExchange.Redis佇列,釋出與訂閱,分散式鎖的簡單使用NetCoreRedis佇列分散式