婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)

基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)

熱門標簽:北京400電話辦理收費標準 鄭州人工智能電銷機器人系統(tǒng) 十堰營銷電銷機器人哪家便宜 日本中國地圖標注 超呼電話機器人 魔獸2青云地圖標注 山東外呼銷售系統(tǒng)招商 貴州電銷卡外呼系統(tǒng) 宿遷便宜外呼系統(tǒng)平臺

1、前言

在Java中,我們通過鎖來避免由于競爭而造成的數(shù)據(jù)不一致問題。通常我們使用synchronized 、Lock來實現(xiàn)。但是Java中的鎖只能保證在同一個JVM進程內(nèi)中可用,在跨JVM進程,例如分布式系統(tǒng)上則不可靠了。

2、分布式鎖

分布式鎖,是一種思想,它的實現(xiàn)方式有很多,如基于數(shù)據(jù)庫實現(xiàn)、基于緩存(Redis等)實現(xiàn)、基于Zookeeper實現(xiàn)等等。為了確保分布式鎖可用,我們至少要確保鎖的實現(xiàn)同時滿足以下四個條件

  • 互斥性:在任意時刻,只有一個客戶端能持有鎖。
  • 不會發(fā)生死鎖:即使客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證后續(xù)其他客戶端能加鎖。
  • 具有容錯性:只要大部分的Redis節(jié)點正常運行,客戶端就可以加鎖和解鎖。
  • 解鈴還須系鈴人:加鎖和解鎖必須是同一個客戶端,客戶端自己不能把別人加的鎖給解了。

 3、基于Redis實現(xiàn)分布式鎖

以下代碼實現(xiàn)了基于redis中間件的分布式鎖。加鎖的過程中為了保障setnx(設(shè)置KEY)和expire(設(shè)置超時時間)盡可能在一個事務(wù)中,使用到了lua腳本的方式,將需要完成的指令一并提交到redis中;

3.1、RedisConfig.java

package com.demo.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplateString, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplateString, Object> template = new RedisTemplate>();
        template.setConnectionFactory(factory);
        // key采用String的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // value序列化方式采用jackson
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

}

3.2、RedisLockController.java

package com.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;

@RestController
@RequestMapping("/redis")
public class RedisLockController {

    @Autowired
    private RedisTemplateString, Object> redisTemplate;

    @RequestMapping(value = "/lock/{key}/{uid}/{expire}")
    public Long lock(@PathVariable("key") String key, @PathVariable("uid") String uid, @PathVariable("expire") Integer expire) {
        Long result = null;
        try {
            //調(diào)用lua腳本并執(zhí)行
            DefaultRedisScriptLong> redisScript = new DefaultRedisScript>();
            redisScript.setResultType(Long.class);//返回類型是Long
            //lua文件存放在resources目錄下的redis文件夾內(nèi)
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock.lua")));
            result = redisTemplate.execute(redisScript, Arrays.asList(key), uid, expire);
            System.out.println("lock==" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @RequestMapping(value = "/unlock/{key}/{uid}")
    public Long unlock(@PathVariable("key") String key, @PathVariable("uid") String uid) {
        Long result = null;
        try {
            //調(diào)用lua腳本并執(zhí)行
            DefaultRedisScriptLong> redisScript = new DefaultRedisScript>();
            redisScript.setResultType(Long.class);//返回類型是Long
            //lua文件存放在resources目錄下的redis文件夾內(nèi)
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_unlock.lua")));
            result = redisTemplate.execute(redisScript, Arrays.asList(key), uid);
            System.out.println("unlock==" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

}

3.3、redis_lock.lua

if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
    return redis.call('expire',KEYS[1],ARGV[2])
else
    return 0
end

3.4、redis_unlock.lua

if redis.call("exists",KEYS[1]) == 0 then
    return 1
end

if redis.call('get',KEYS[1]) == ARGV[1] then
    return redis.call('del',KEYS[1])
else
    return 0
end

4、測試效果

key123為key,thread12345為value標識鎖的主人,300為該鎖的超時時間

加鎖:鎖主人為thread12345
http://127.0.0.1:8080/redis/lock/key123/thread12345/300

解鎖:解鎖人為thread123456
http://127.0.0.1:8080/redis/unlock/key123/thread123456

解鎖:解鎖人為thread12345
http://127.0.0.1:8080/redis/unlock/key123/thread12345

4.1、加鎖,其他人解鎖


thread12345加的鎖,thread123456是解不了的,只有等thread12345自己解鎖或者鎖的超時時間過期

4.2、加鎖,自己解鎖


thread12345加的鎖,thread12345自己隨時可以解鎖,也可以等鎖的超時時間過期

5、總結(jié)

  •  使用Redis鎖,會有業(yè)務(wù)未執(zhí)行完,鎖過期的問題,也就是鎖不具有可重入性的特點。
  • 使用Redis鎖,在嘗試獲取鎖的時候,是非阻塞的,不滿足在一定期限內(nèi)不斷嘗試獲取鎖的場景。
  • 以上兩點,都可以采用Redisson鎖解決。

到此這篇關(guān)于基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)的文章就介紹到這了,更多相關(guān)Redis實現(xiàn)分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解redis分布式鎖的這些坑
  • SpringBoot之使用Redis實現(xiàn)分布式鎖(秒殺系統(tǒng))
  • 詳解Redis 分布式鎖遇到的序列化問題
  • 詳解RedisTemplate下Redis分布式鎖引發(fā)的系列問題
  • redisson分布式鎖的用法大全
  • php基于redis的分布式鎖實例詳解
  • Redis分布式鎖升級版RedLock及SpringBoot實現(xiàn)方法
  • 利用redis實現(xiàn)分布式鎖,快速解決高并發(fā)時的線程安全問題
  • 詳解基于redis實現(xiàn)分布式鎖

標簽:朝陽 楊凌 大慶 吉安 果洛 江蘇 臺州 北京

巨人網(wǎng)絡(luò)通訊聲明:本文標題《基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)》,本文關(guān)鍵詞  基于,Redis,實現(xiàn),分布式,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)》相關(guān)的同類信息!
  • 本頁收集關(guān)于基于Redis實現(xiàn)分布式鎖的方法(lua腳本版)的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 弥勒县| 綦江县| 山阳县| 华阴市| 闽侯县| 长兴县| 琼中| 体育| 华宁县| 汕尾市| 镇雄县| 南木林县| 吉水县| 常德市| 东乡县| 梅河口市| 昌江| 高阳县| 石台县| 新乐市| 瑞丽市| 大新县| 霍邱县| 深圳市| 开原市| 津市市| 化州市| 青海省| 龙门县| 页游| 颍上县| 东乌珠穆沁旗| 平乡县| 武川县| 离岛区| 上犹县| 湄潭县| 邵武市| 涟源市| 普定县| 登封市|