Redis分佈式鎖

redis:Redis是開源,內存存儲的數據結構服務器,可用做數據庫,高速緩存和消息隊列代理.
採用單進程單線程模型,併發能力強大,主流的分佈式緩存工具。
做用:減去數據庫訪問的壓力。
redis應用:1.token生成2.session共享3.分佈式鎖4.自增id5.驗證碼redis

加鎖

經過setnx向特定的key值寫入一個隨機值,而且同時設置失效時間,寫值成功即加鎖成功.spring

注意點數據庫

  • 1.必須給鎖加一個失效時間,避免死鎖.
  • 2.加鎖時,每一個節點產生一個隨機字符串,避免誤刪鎖.

好比:A節點加鎖並設置有效時間,A未執行完畢可是鎖已經失效了,B節點趁機加鎖,此時A節點準備執行解鎖動做,若AB節點加鎖寫入的值相等的話會形成A節點去解鎖B節點的鎖,顯然不行.緩存

  • 3.寫入隨機值與設置有效時間必須同時的,是原子操做,防止未設置有效時間.setnx命令

maven依賴:tomcat

<dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.7.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>

解鎖

匹配隨機值,刪除redis上的特定key的數據,要保證刪除動做是原子的,即獲取數據丶判斷一致丶及刪除數據三個操做是原子的。執行以下lua腳本:
ARV[1]是value值服務器

if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
lua腳本丟到服務器上,它認爲是一個操做序列不可分開的序列,redis介紹時說過是一個單進程單線程模型,這點要緊緊記住,所以會經過一個線程執行這個腳本以後纔會去處理別的請求,所以保證了lua腳本保證了原子性.session

代碼實現:
加鎖:數據結構

public boolean tryLock() {
    //隨機生成字符串
    String uuid= UUID.randomUUID().toString();
    //獲取redis原始連接
    Jedis jedis = redisManager.getJedis();
    //使用setnx命令請求寫值,並設置有效時間
    String ret=jedis.set(KEY,uuid,"NX","PX",1000);
    if("OK".equals(ret)){
        //供給unlock時從threadLocal獲取此值,ThreadLocal完成數據共享
        local.set(uuid);
        return  true;
    }
    return false;
}

解鎖:mybatis

public void unlock() {

        //讀取lua腳本
        String script= FileUtils.readFileByLines("lua腳本路徑");
        Jedis jedis=redisManager.getJedis();
         //連接redis執行Lua腳本,value值沒法從unlock方法入參了,所以用threadLocal來獲取
        jedis.eval(script, Arrays.asList(KEY),Arrays.asList(local.get()));
        
    }

這裏是簡單的代碼實現具體講怎麼用jedis執行對應的方法,方法不齊的能夠自行查閱資料併發

順便簡單講下ThreadLoacl
//1/作線程級的數據傳遞,在spring.mybatis隨處可見
//2.好比spring的事務傳播屬性就是經過threadLocal來傳遞的
//3.tomcat的session也是放在threadLocal的
private static ThreadLocal<String> local = new ThreadLocal<>();
相關文章
相關標籤/搜索