基於redis的普通分佈式鎖

1、業界有哪些主流的分佈式鎖實現方案?

目前主流的有三種,如下:

- 基於數據庫實現

基於數據庫來做分佈式鎖的話,通常是採用數據庫的樂觀鎖或悲觀鎖來實現。

- 基於ZooKeeper實現

基於ZooKeeper,是採用它的臨時有序節點來實現的分佈式鎖。

- 基於Redis實現

基於Redis實現的鎖機制,主要是依賴redis自身的原子來實現

以上三種方式都可以實現分佈式鎖,如果併發量不大的話,直接採用數據庫就可以,如果高併發的話,就要考慮zookeeper或redis,但從高併發高性能角度考慮,基於 Redis 實現性能會更好;所以如何選擇,還是取決於業務需求。

2、下面介紹基於redis的普通分佈式鎖

SET key value [NX] [XX] [EX <seconds>] [PX [millseconds]] 

以上set 代替了 setnx +expire 需要分2次執行命令操作的方式,保證了原子性

127.0.0.1:6379> set lock true NX px 600000

OK

127.0.0.1:6379> set lock true NX px 600000

(nil)

 

如果setnx 返回ok 說明拿到了鎖

如果setnx 返回 nil,說明拿鎖失敗,被其他線程佔用。

3、案例實戰:基於redis的分佈式鎖實現下訂單防止重複提交

@PostMapping(value = "/createOrder", produces = APPLICATION_JSON_UTF8_VALUE, consumes = APPLICATION_JSON_UTF8_VALUE)
public String createOrder(@RequestBody  OrderDTO obj) {

    //步驟1:先轉換爲唯一MD5
    String json=JsonUtil.object2Json(obj);
    String md5 = DigestUtils.md5DigestAsHex(json.getBytes()).toUpperCase();

    //步驟2:把md5設置爲分佈式鎖的key
    /**
     * setIfAbsent 的作用就相當於 SET key value [NX] [XX] [EX <seconds>] [PX [millseconds]]
     * 設置過期
     */
    Boolean bo=stringRedisTemplate.opsForValue().setIfAbsent(md5,"1",60, TimeUnit.SECONDS);
    if(bo){
        // 加鎖成功
        log.debug("{}拿鎖成功,開始處理業務",md5);
        try {
            //模擬10秒 業務處理
            Thread.sleep(1000*10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //不要刪除,萬一業務處理時間很短,頁面上點了兩次,點第二次的時候,第一次已經處理完了,這樣就同一張單子處理了兩次,還是等他過期比較好
        //stringRedisTemplate.delete(md5);
        log.debug("{}拿鎖成功,結束處理業務",md5);
        return "ok";
    }else{
        log.debug("{}拿鎖失敗",md5);
        //拿不鎖,直接退出
        return  "請不要重複點擊!";
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章