最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

redis分布式鎖解決表單重復(fù)提交的問題

 更新時間:2021年11月28日 15:16:13   作者:wb_csdn_job  
在系統(tǒng)中,有些接口如果重復(fù)提交,可能會造成臟數(shù)據(jù)或者其他的嚴(yán)重的問題,所以我們一般會對與數(shù)據(jù)庫有交互的接口進(jìn)行重復(fù)處理。本文就詳細(xì)的介紹一下redis分布式鎖解決表單重復(fù)提交,感興趣的可以了解一下

假如用戶的網(wǎng)速慢,用戶點擊提交按鈕,卻因為網(wǎng)速慢,而沒有跳轉(zhuǎn)到新的頁面,這時的用戶會再次點擊提交按鈕,舉個例子:用戶點擊訂單頁面,當(dāng)點擊提交按鈕的時候,也許因為網(wǎng)速的原因,沒有跳轉(zhuǎn)到新的頁面,這時的用戶會再次點擊提交按鈕,如果沒有經(jīng)過處理的話,這時用戶就會生成兩份訂單,類似于這種場景都叫重復(fù)提交。

使用redis的setnx和getset命令解決表單重復(fù)提交的問題。

1.引入redis依賴和aop依賴

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.3.8.RELEASE</version>
        </dependency>

		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

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 進(jìn)行加鎖的操作(該方法是單線程運行的)
     * @date 2019年09月20日
     * @param key 某個方法請求url加上cookie中的用戶身份使用md5加密生成
     * @param value 當(dāng)前時間+過期時間(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()){
            //獲取上一個鎖的時間,并且重新設(shè)置鎖
            String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
            if(StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue)){
                //設(shè)置成功,重新設(shè)置鎖是保證了單線程的運行
                return true;
            }
        }
        return false;
    }

    /**
     * @author wangbin
     * @description 進(jìn)行解鎖的操作
     * @date 2019年09月20日
     * @param key 某個方法請求url使用md5加密生成
     * @param value 當(dāng)前時間+過期時間
     * @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 進(jìn)行解鎖的操作
     * @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.使用攔截器在請求之前進(jìn)行加鎖的判斷。

@Configuration
public class LoginInterceptor extends HandlerInterceptorAdapter {
    private final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    //超時時間設(shè)置為10秒
    private static final int timeOut = 10000;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisLock redisLock;
    /**
     * 在請求處理之前進(jìn)行調(diào)用(Controller方法調(diào)用之前)
     * 基于URL實現(xiàn)的攔截器
     * @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,權(quán)限判斷等
            //判斷是否是重復(fù)提交的請求
			if(!redisLock.lock(DigestUtils.md5Hex(request.getRequestURI()+value),String.valueOf(System.currentTimeMillis()+timeOut))){
                        logger.info("===========獲取鎖失敗,該請求為重復(fù)提交請求");
                        return false;
 			 }
            return true;
        }
    }
}

4.使用aop在后置通知中進(jìn)行解鎖。

/**
 * @author wangbin
 * @description 使用redis分布式鎖解決表單重復(fù)提交的問題
 * @date 2019年09月20日
 */
@Aspect
@Component
public class RepeatedSubmit {

    @Autowired
    private RedisLock redisLock;

    //定義切點
    @Pointcut("execution(public * com.kunluntop.logistics.controller..*.*(..))")
    public void pointcut(){

    }

    //在方法執(zhí)行完成后釋放鎖
    @After("pointcut()")
    public void after(){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        redisLock.unLock(DigestUtils.md5Hex(request.getRequestURI()+ CookieUtils.getCookie(request,"userkey")));
    }
}

到此這篇關(guān)于redis分布式鎖解決表單重復(fù)提交的問題的文章就介紹到這了,更多相關(guān)redis 表單重復(fù)提交內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Java中Lambda表達(dá)式的相關(guān)操作

    淺談Java中Lambda表達(dá)式的相關(guān)操作

    java8新特性,Lambda是一個匿名函數(shù),類似Python中的Lambda表達(dá)式、js中的箭頭函數(shù),目的簡化操作,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 解決@RequestBody搭配@Data的大坑

    解決@RequestBody搭配@Data的大坑

    這篇文章主要介紹了解決@RequestBody搭配@Data的大坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java程序生成Access文件代碼實例

    Java程序生成Access文件代碼實例

    這篇文章主要介紹了Java程序生成Access文件代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Java中如何靈活獲取excel中的數(shù)據(jù)

    Java中如何靈活獲取excel中的數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于Java中如何靈活獲取excel中的數(shù)據(jù),在日常工作中我們常常會進(jìn)行文件讀寫操作,除去我們最常用的純文本文件讀寫,更多時候我們需要對Excel中的數(shù)據(jù)進(jìn)行讀取操作,需要的朋友可以參考下
    2023-07-07
  • java實現(xiàn)Z字形掃描程序

    java實現(xiàn)Z字形掃描程序

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)Z字形掃描程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Spring Security認(rèn)證機(jī)制源碼層探究

    Spring Security認(rèn)證機(jī)制源碼層探究

    SpringSecurity是基于Filter實現(xiàn)認(rèn)證和授權(quán),底層通過FilterChainProxy代理去調(diào)用各種Filter(Filter鏈),F(xiàn)ilter通過調(diào)用AuthenticationManager完成認(rèn)證 ,通過調(diào)用AccessDecisionManager完成授權(quán)
    2023-03-03
  • Java中TypeReference用法詳情說明

    Java中TypeReference用法詳情說明

    這篇文章主要介紹了Java中TypeReference用法詳情說明,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07
  • 面試中遇到的java逃逸分析問題

    面試中遇到的java逃逸分析問題

    這篇文章主要介紹了面試中遇到的java逃逸分析問題,逃逸分析(Escape Analysis)簡單來講就是,Java Hotspot 虛擬機(jī)可以分析新創(chuàng)建對象的使用范圍,并決定是否在 Java 堆上分配內(nèi)存的一項技術(shù)。,需要的朋友可以參考下
    2019-06-06
  • Java二叉樹的四種遍歷方式詳解

    Java二叉樹的四種遍歷方式詳解

    這篇文章主要介紹了Java二叉樹的四種遍歷,二叉樹的遍歷可以分為前序、中序、后序、層次遍歷,需要的朋友可以參考下
    2021-11-11
  • Netty分布式ByteBuf使用SocketChannel讀取數(shù)據(jù)過程剖析

    Netty分布式ByteBuf使用SocketChannel讀取數(shù)據(jù)過程剖析

    這篇文章主要為大家介紹了Netty源碼分析ByteBuf使用SocketChannel讀取數(shù)據(jù)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03

最新評論

墨竹工卡县| 阜康市| 开远市| 博湖县| 平凉市| 芦山县| 拜城县| 峡江县| 上思县| 伊吾县| 桓仁| 锡林郭勒盟| 蕉岭县| 黄龙县| 南开区| 温州市| 商丘市| 长寿区| 望江县| 启东市| 金山区| 海原县| 峡江县| 新晃| 县级市| 昭觉县| 宜城市| 阳泉市| 东安县| 牙克石市| 崇信县| 新密市| 陈巴尔虎旗| 介休市| 松潘县| 鸡东县| 鲁甸县| 普陀区| 永善县| 襄垣县| 伊通|