国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

山東農(nóng)業(yè)大學(xué)學(xué)風(fēng)建設(shè)專(zhuān)題網(wǎng)站網(wǎng)頁(yè)模版

山東農(nóng)業(yè)大學(xué)學(xué)風(fēng)建設(shè)專(zhuān)題網(wǎng)站,網(wǎng)頁(yè)模版,南通通州區(qū)網(wǎng)站制作,在網(wǎng)站上做封面一、背景 與分布式鎖相對(duì)應(yīng)的是「單機(jī)鎖」,我們?cè)趯?xiě)多線程程序時(shí),避免同時(shí)操作一個(gè)共享變量產(chǎn)生數(shù)據(jù)問(wèn)題,通常會(huì)使用一把鎖來(lái)「互斥」,以保證共享變量的正確性,其使用范圍是在「同一個(gè)進(jìn)程」中。單機(jī)環(huán)境下&#xff0…

一、背景

  • 與分布式鎖相對(duì)應(yīng)的是「單機(jī)鎖」,我們?cè)趯?xiě)多線程程序時(shí),避免同時(shí)操作一個(gè)共享變量產(chǎn)生數(shù)據(jù)問(wèn)題,通常會(huì)使用一把鎖來(lái)「互斥」,以保證共享變量的正確性,其使用范圍是在「同一個(gè)進(jìn)程」中。
  • 單機(jī)環(huán)境下,我們常用 synchronized 或者 Lock 鎖解決多線程并發(fā)訪問(wèn)產(chǎn)生的數(shù)據(jù)安全問(wèn)題,但是如果是在集群環(huán)境,本地鎖就會(huì)失效。
  • 為解決分布式場(chǎng)景下的并發(fā)問(wèn)題, 就需要用到分布式鎖。下面介紹下Redis分布式鎖。

二、實(shí)現(xiàn)思路

1. 如何實(shí)現(xiàn)互斥?

為達(dá)到互斥,可以使用SETNX 命令,這個(gè)命令表示Set If Not Exists,即如果 key 不存在,才會(huì)設(shè)置它的值,否則什么也不做。
如:

	SETNX lock 1    //加鎖DEL lock //釋放鎖

但是這樣有個(gè)問(wèn)題,當(dāng)客戶(hù)端 1 拿到鎖后,如果發(fā)生下面的場(chǎng)景,就會(huì)造成「死鎖」:
①程序處理業(yè)務(wù)邏輯異常,未釋放鎖
②拿到鎖后進(jìn)程掛了,沒(méi)機(jī)會(huì)釋放鎖
這時(shí),這個(gè)客戶(hù)端就會(huì)一直占用這個(gè)鎖,而其它客戶(hù)端就「永遠(yuǎn)」拿不到這把鎖了。

2. 如何避免死鎖?

鎖無(wú)法釋放,產(chǎn)生「死鎖」。那么我們給這個(gè)鎖加個(gè)「租期」,讓它在一定時(shí)間內(nèi)如果一直沒(méi)釋放就過(guò)期,問(wèn)題不就解決了。Redis支持這種語(yǔ)法,示例:

SETNX lock 1    // 加鎖
EXPIRE lock 10  // 10s后自動(dòng)過(guò)期

但這樣真的沒(méi)問(wèn)題了嗎?
No!

現(xiàn)在的操作,加鎖、設(shè)置過(guò)期是 2 條命令,有沒(méi)有可能只執(zhí)行了第一條,第二條卻「來(lái)不及」執(zhí)行的情況發(fā)生呢?例如:
①SETNX 執(zhí)行成功,執(zhí)行 EXPIRE 時(shí)由于網(wǎng)絡(luò)問(wèn)題,執(zhí)行失敗
②SETNX 執(zhí)行成功,Redis 異常宕機(jī),EXPIRE 沒(méi)有機(jī)會(huì)執(zhí)行
③SETNX 執(zhí)行成功,客戶(hù)端異常崩潰,EXPIRE 也沒(méi)有機(jī)會(huì)執(zhí)行
總之,這兩條命令不能保證是原子操作(一起成功),就有潛在的風(fēng)險(xiǎn)導(dǎo)致過(guò)期時(shí)間設(shè)置失敗,依舊發(fā)生「死鎖」問(wèn)題。

如何解決?
Redis 2.6.12 之后,Redis 擴(kuò)展了 SET 命令的參數(shù),用這一條命令就可以執(zhí)行上述兩步操作:

	// 一條命令保證原子性執(zhí)行SET lock 1 EX 10 NX

我們?cè)賮?lái)看分析下,它還有什么問(wèn)題?
試想這樣一種場(chǎng)景:
①客戶(hù)端 1 加鎖成功,開(kāi)始操作共享資源
②客戶(hù)端 1 操作共享資源的時(shí)間,「超過(guò)」了鎖的過(guò)期時(shí)間,鎖被「自動(dòng)釋放」
③客戶(hù)端 2 加鎖成功,開(kāi)始操作共享資源
④客戶(hù)端 1 操作共享資源完成,釋放鎖(但釋放的是客戶(hù)端 2 的鎖)

這里存在兩個(gè)嚴(yán)重的問(wèn)題:
鎖過(guò)期:客戶(hù)端 1 操作共享資源耗時(shí)太久,導(dǎo)致鎖被自動(dòng)釋放,之后被客戶(hù)端 2 持有
釋放別人的鎖:客戶(hù)端 1 操作共享資源完成后,卻又釋放了客戶(hù)端 2 的鎖

3. 鎖被別人釋放怎么辦?

解決辦法是:客戶(hù)端在加鎖時(shí),設(shè)置一個(gè)只有自己知道的「唯一標(biāo)識(shí)」進(jìn)去。釋放時(shí),先判斷這把鎖是否是自己所有,是的話再進(jìn)行釋放。
這樣涉及到兩步操作:
①判斷這把鎖是否是自己所有;
②釋放鎖。
非原子性,也會(huì)出現(xiàn)并發(fā)問(wèn)題,如何解決呢?Lua腳本
我們可以寫(xiě)好Lua腳本后交給Redis執(zhí)行,腳本如下:

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

4. 鎖過(guò)期怎么辦?

方案:

  • 可能是我們?cè)u(píng)估操作共享資源的時(shí)間不準(zhǔn)確導(dǎo)致的。可以「冗余」適量過(guò)期時(shí)間,降低鎖提前過(guò)期的概率。
  • 加鎖時(shí),先設(shè)置一個(gè)過(guò)期時(shí)間,然后我們開(kāi)啟一個(gè)「守護(hù)線程」,定時(shí)去檢測(cè)這個(gè)鎖的失效時(shí)間,如果鎖快要過(guò)期了,操作共享資源還未完成,那么就自動(dòng)對(duì)鎖進(jìn)行「續(xù)期」,重新設(shè)置過(guò)期時(shí)間。

備注:個(gè)人根據(jù)項(xiàng)目的業(yè)務(wù)情況,考慮「鎖過(guò)期」對(duì)業(yè)務(wù)的影響,看是否需要續(xù)期。

5. Redisson

Redisson 是一個(gè) Java 語(yǔ)言實(shí)現(xiàn)的 Redis SDK 客戶(hù)端,在使用分布式鎖時(shí),它就采用了「自動(dòng)續(xù)期」的方案來(lái)避免鎖過(guò)期,這個(gè)守護(hù)線程我們一般也把它叫做「看門(mén)狗」線程。
Ression原理
除此之外,這個(gè) SDK 還封裝了很多易用的功能:

  • 可重入鎖
  • 樂(lè)觀鎖
  • 公平鎖
  • 讀寫(xiě)鎖
  • Redlock

6. Redlock

之前分析的場(chǎng)景都是,鎖在「單個(gè)」Redis 實(shí)例中可能產(chǎn)生的問(wèn)題,并沒(méi)有涉及到 Redis 的部署架構(gòu)細(xì)節(jié)。
而我們?cè)谑褂?Redis 時(shí),一般會(huì)采用主從集群 + 哨兵的模式部署,這樣做的好處在于,當(dāng)主庫(kù)異常宕機(jī)時(shí),哨兵可以實(shí)現(xiàn)「故障自動(dòng)切換」,把從庫(kù)提升為主庫(kù),繼續(xù)提供服務(wù),以此保證可用性。
那當(dāng)「主從發(fā)生切換」時(shí),這個(gè)分布鎖會(huì)依舊安全嗎?

試想這樣的場(chǎng)景:

  1. 客戶(hù)端 1 在主庫(kù)上執(zhí)行 SET 命令,加鎖成功
  2. 此時(shí),主庫(kù)異常宕機(jī),SET 命令還未同步到從庫(kù)上(主從復(fù)制是異步的)
  3. 從庫(kù)被哨兵提升為新主庫(kù),這個(gè)鎖在新的主庫(kù)上,丟失了!
    Redis分布式鎖集群?jiǎn)栴}
    為此,Redis 的作者提出一種解決方案,就是我們經(jīng)常聽(tīng)到的 Redlock(紅鎖)。

Redlock 的方案基于 2 個(gè)前提:

不再需要部署從庫(kù)和哨兵實(shí)例,只部署主庫(kù)
但主庫(kù)要部署多個(gè),官方推薦至少 5 個(gè)實(shí)例
也就是說(shuō),想用使用 Redlock,你至少要部署 5 個(gè) Redis 實(shí)例,而且都是主庫(kù),它們之間沒(méi)有任何關(guān)系,都是一個(gè)個(gè)孤立的實(shí)例。
注意:不是部署 Redis Cluster,就是部署 5 個(gè)簡(jiǎn)單的 Redis 實(shí)例。

Redlock流程是這樣的,一共分為 5 步:

  1. 客戶(hù)端先獲取「當(dāng)前時(shí)間戳T1」
  2. 客戶(hù)端依次向這 5 個(gè) Redis 實(shí)例發(fā)起加鎖請(qǐng)求(用前面講到的 SET 命令),且每個(gè)請(qǐng)求會(huì)設(shè)置超時(shí)時(shí)間(毫秒級(jí),要遠(yuǎn)小于鎖的有效時(shí)間),如果某一個(gè)實(shí)例加鎖失敗(包括網(wǎng)絡(luò)超時(shí)、鎖被其它人持有等各種異常情況),就立即向下一個(gè) Redis 實(shí)例申請(qǐng)加鎖
  3. 如果客戶(hù)端從 >=3 個(gè)(大多數(shù))以上 Redis 實(shí)例加鎖成功,則再次獲取「當(dāng)前時(shí)間戳T2」,如果 T2 - T1 < 鎖的過(guò)期時(shí)間,此時(shí),認(rèn)為客戶(hù)端加鎖成功,否則認(rèn)為加鎖失敗
  4. 加鎖成功,去操作共享資源(例如修改 MySQL 某一行,或發(fā)起一個(gè) API 請(qǐng)求)
  5. 加鎖失敗,向「全部節(jié)點(diǎn)」發(fā)起釋放鎖請(qǐng)求(前面講到的 Lua 腳本釋放鎖)

上述過(guò)程有4個(gè)重點(diǎn):

  1. 客戶(hù)端在多個(gè) Redis 實(shí)例上申請(qǐng)加鎖
  2. 必須保證大多數(shù)節(jié)點(diǎn)加鎖成功
  3. 大多數(shù)節(jié)點(diǎn)加鎖的總耗時(shí),要小于鎖設(shè)置的過(guò)期時(shí)間
  4. 釋放鎖,要向全部節(jié)點(diǎn)發(fā)起釋放鎖請(qǐng)求

實(shí)際生產(chǎn)中,Redlock很少使用,所以就簡(jiǎn)單介紹到這里。

三、springboot項(xiàng)目實(shí)現(xiàn)Redis分布式鎖

1. 依賴(lài)

	<!--Springboot依賴(lài) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.12.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --><!--Springboot 測(cè)試依賴(lài) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.3.12.RELEASE</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --><!--Springboot Redis依賴(lài) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.3.12.RELEASE</version><!--排除掉默認(rèn)的 lettuce ,lettuce 在使用中存在偶爾連接超時(shí)問(wèn)題--><exclusions><exclusion><artifactId>lettuce-core</artifactId><groupId>io.lettuce</groupId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.2.0</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons --><!-- Redis 需要引入這個(gè)依賴(lài),否則報(bào)錯(cuò) --><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-commons</artifactId><version>2.3.9.RELEASE</version></dependency>

2. Redis配置類(lèi)

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;import java.util.HashSet;
import java.util.Set;@Configuration
public class RedisConfig {@Value("${spring.redis.cluster.nodes:IP:Port}")private String clusterNodes;@Value("${spring.redis.cluster.max-redirects:3}")private int maxRedirects;@Value("${spring.redis.password:***}")private String password;@Value("${spring.redis.timeout:3000}")private int timeout;/*** 最大空閑數(shù)*/@Value("${spring.redis.maxIdle:100}")private int maxIdle;/*** 控制一個(gè)pool可分配多少個(gè)jedis實(shí)例*/@Value("${spring.redis.maxTotal:100}")private int maxTotal;/*** 最大建立連接等待時(shí)間。如果超過(guò)此時(shí)間將接到異常。設(shè)為-1表示無(wú)限制*/@Value("${spring.redis.maxWaitMillis:5000}")private int maxWaitMillis;/*** 最小空閑數(shù)*/@Value("${spring.redis.minIdle:5}")private int minIdle;/*** 連接的最小空閑時(shí)間 默認(rèn)1800000毫秒(30分鐘)*/@Value("${spring.redis.minEvictableIdleTimeMillis:300000}")private int minEvictableIdleTimeMillis;/*** 每次釋放連接的最大數(shù)目,默認(rèn)3*/@Value("${spring.redis.numTestsPerEvictionRun:3}")private int numTestsPerEvictionRun;/*** 逐出掃描的時(shí)間間隔(毫秒) 如果為負(fù)數(shù),則不運(yùn)行逐出線程, 默認(rèn)-1*/@Value("${spring.redis.timeBetweenEvictionRunsMillis:30000}")private int timeBetweenEvictionRunsMillis;/*** 是否在從池中取出連接前進(jìn)行檢驗(yàn),如果檢驗(yàn)失敗,則從池中去除連接并嘗試取出另一個(gè)*/@Value("${spring.redis.testOnBorrow:true}")private boolean testOnBorrow;/*** 在空閑時(shí)檢查有效性, 默認(rèn)false*/@Value("${spring.redis.testWhileIdle:true}")private boolean testWhileIdle;@Beanpublic JedisPoolConfig getJedisPoolConfig() {JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();// 最大空閑數(shù)jedisPoolConfig.setMaxIdle(maxIdle);// 最小空閑數(shù)jedisPoolConfig.setMinIdle(minIdle);// 連接池的最大數(shù)據(jù)庫(kù)連接數(shù)jedisPoolConfig.setMaxTotal(maxTotal);// 最大建立連接等待時(shí)間jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);// 逐出連接的最小空閑時(shí)間 默認(rèn)1800000毫秒(30分鐘)jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);// 每次逐出檢查時(shí) 逐出的最大數(shù)目 如果為負(fù)數(shù)就是 : 1/abs(n), 默認(rèn)3jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);// 逐出掃描的時(shí)間間隔(毫秒) 如果為負(fù)數(shù),則不運(yùn)行逐出線程, 默認(rèn)-1jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);// 是否在從池中取出連接前進(jìn)行檢驗(yàn),如果檢驗(yàn)失敗,則從池中去除連接并嘗試取出另一個(gè)jedisPoolConfig.setTestOnBorrow(testOnBorrow);// 在空閑時(shí)檢查有效性, 默認(rèn)falsejedisPoolConfig.setTestWhileIdle(testWhileIdle);return jedisPoolConfig;}/*** Redis集群的配置** @return RedisClusterConfiguration*/@Beanpublic RedisClusterConfiguration redisClusterConfiguration() {RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();// Set<RedisNode> clusterNodesString[] serverArray = clusterNodes.split(",");Set<RedisNode> nodes = new HashSet<>();for (String ipPort : serverArray) {String[] ipAndPort = ipPort.split(":");nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1])));}redisClusterConfiguration.setClusterNodes(nodes);redisClusterConfiguration.setMaxRedirects(maxRedirects);redisClusterConfiguration.setPassword(RedisPassword.of(password));return redisClusterConfiguration;}/*** redis連接工廠類(lèi)** @return JedisConnectionFactory*/@Beanpublic JedisConnectionFactory jedisConnectionFactory() {// 集群模式return new JedisConnectionFactory(redisClusterConfiguration(), getJedisPoolConfig());}@Beanpublic RedisTemplate<String, String> poolRedisTemplate() {RedisTemplate<String, String> template = new RedisTemplate<>();template.setConnectionFactory(jedisConnectionFactory());// 如果不配置Serializer,那么存儲(chǔ)的時(shí)候缺省使用String,如果用User類(lèi)型存儲(chǔ),那么會(huì)提示錯(cuò)誤User can't cast to String!StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(mapper);template.setKeySerializer(stringRedisSerializer);template.setHashKeySerializer(stringRedisSerializer);template.setValueSerializer(jackson2JsonRedisSerializer);template.setHashValueSerializer(new StringRedisSerializer());template.setDefaultSerializer(jackson2JsonRedisSerializer);template.setEnableDefaultSerializer(true);template.afterPropertiesSet();return template;}
}

3. Redis 分布式鎖

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class RedisService {@Autowired@Qualifier("poolRedisTemplate")private RedisTemplate<String, String> stringRedisTemplate;public String getStr(String key) {return stringRedisTemplate.opsForValue().get(key);}/*** key 不存在 則進(jìn)行設(shè)置* <p>* 原子性操作** @param k       鍵* @param v       值* @param timeout 超時(shí)時(shí)間* @param unit    超時(shí)時(shí)間的單位* @return key存在返回false,設(shè)置失敗*/public Boolean setIfAbsent(String k, String v, long timeout, TimeUnit unit) {return stringRedisTemplate.opsForValue().setIfAbsent(k, v, timeout, unit);}/*** 加分布式鎖** @param key     鎖* @param timeout 超時(shí)時(shí)間,單位:秒* @return 空串 表示加鎖失敗, uuid 表示加鎖成功,后續(xù)uuid要作為解鎖的標(biāo)識(shí)*/public String tryLock(String key, long timeout) {//釋放鎖時(shí)要根據(jù)uuid判斷是否是自己的鎖,防止釋放其他人的鎖
//        String uuid = System.currentTimeMillis() + "";String uuid = UUID.randomUUID().toString();Boolean tryLock = setIfAbsent(key, uuid, timeout, TimeUnit.SECONDS);if (tryLock) {return uuid;}//加鎖失敗,返回 空串return "";}/*** “判斷值與舊值是否相等,相等則刪除鍵” 的 Lua 腳本,保證原子性操作*/private static final String SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";/*** 釋放分布式鎖** @param key      鎖* @param oldValue 加鎖時(shí)放入的標(biāo)識(shí)* @return 返回釋放鎖成功失敗*/public Boolean unLock(String key, String oldValue) {List<String> keys = new ArrayList<>();keys.add(key);List<String> args = new ArrayList<>();//這里需要加下引號(hào),原因:stringRedisTemplate獲取的值帶引號(hào)(即redis.call('get', KEYS[1]) 的結(jié)果帶引號(hào)),而ARGV[1]不帶引號(hào),比較時(shí)會(huì)出現(xiàn)不等的問(wèn)題args.add("\"" + oldValue + "\"");Long result = stringRedisTemplate.execute((RedisCallback<Long>) connection -> {Object nativeConnection = connection.getNativeConnection();// 集群模式和單機(jī)模式雖然執(zhí)行腳本的方法一樣,但是沒(méi)有共同的接口,所以只能分開(kāi)執(zhí)行// 集群模式if (nativeConnection instanceof JedisCluster) {return (Long) ((JedisCluster) nativeConnection).eval(SCRIPT, keys, args);}// 單機(jī)模式else if (nativeConnection instanceof Jedis) {return (Long) ((Jedis) nativeConnection).eval(SCRIPT, keys, args);}return 0L;});return result == 1L;}}

4. 測(cè)試類(lèi)

import com.example.demo.redis.RedisService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StringUtils;@SpringBootTest
public class RedisTest {@Autowiredprivate RedisService redisService;@Testpublic void test() {String key = "test-lock-1235637";String uid = redisService.tryLock(key, 10000);if(StringUtils.isEmpty(uid)){return;}System.out.println(uid);String uid2 = redisService.tryLock("test-lock-123", 3000);System.out.println("重新獲得鎖是否成功:" + !StringUtils.isEmpty(uid2));try {//執(zhí)行業(yè)務(wù)代碼System.out.println("111111111");} finally {Boolean unlockSuccess = redisService.unLock(key, uid);System.out.println("解鎖結(jié)果:" + unlockSuccess);System.out.println(redisService.getStr(key));}}
}

四、springboot項(xiàng)目中Redission的簡(jiǎn)單使用

1. 依賴(lài)

<!--redission相關(guān)依賴(lài)--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.0</version></dependency>

2. 配置類(lèi)

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissionConfig {@Beanpublic RedissonClient getRedisson() {
//        //單機(jī)
//        Config config = new Config();
//        //單機(jī)模式  依次設(shè)置redis地址和密碼
//        config.useSingleServer().
//                setAddress("redis://" + host + ":" + port);
//        RedissonClient redisson = Redisson.create(config);
//
//        //主從
//        Config config = new Config();
//        config.useMasterSlaveServers()
//                .setMasterAddress("redis://127.0.0.1:6379")
//                .addSlaveAddress("redis://127.0.0.1:6389", "127.0.0.1:6332", "127.0.0.1:6419")
//                .addSlaveAddress("redis://127.0.0.1:6399");
//        RedissonClient redisson = Redisson.create(config);
//
//
//        //哨兵
//        Config config = new Config();
//        config.useSentinelServers()
//                .setMasterName("mymaster")
//                .addSentinelAddress("redis://127.0.0.1:26389", "127.0.0.1:26379")
//                .addSentinelAddress("redis://127.0.0.1:26319");
//        RedissonClient redisson = Redisson.create(config);//集群  ,,,,,Config config = new Config();config.useClusterServers().setScanInterval(2000) // cluster state scan interval in milliseconds.addNodeAddress("redis://ip:port", "redis://ip:port").setPassword("***");RedissonClient redisson = Redisson.create(config);return redisson;}
}

3. 測(cè)試類(lèi)

import org.junit.jupiter.api.Test;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;@SpringBootTest
public class RedissionTest {@Resourceprivate RedissonClient redisson;@Testpublic void testRedission() {System.out.println("開(kāi)始執(zhí)行");String lockKey = "123456";RLock lock = redisson.getLock(lockKey);System.out.println("獲取鎖");try {//嘗試獲取鎖,參數(shù)分別是:獲取鎖的最大等待時(shí)間(期間會(huì)重試),鎖自動(dòng)釋放時(shí)間,時(shí)間單位boolean b = lock.tryLock(1, 10, TimeUnit.SECONDS);System.out.println("是否獲取鎖:" + b);//執(zhí)行業(yè)務(wù)邏輯System.out.println("執(zhí)行業(yè)務(wù)邏輯....");Thread.sleep(3000);} catch (Exception e) {System.out.println("系統(tǒng)異常,稍后重試....");} finally {//刪除鎖lock.unlock();System.out.println("解鎖成功");}}
}

五、參考文獻(xiàn)

https://mp.weixin.qq.com/s/2et43aJT6qjBsJ8Z9pcZcQ

http://aloenet.com.cn/news/35575.html

相關(guān)文章:

  • 新橋企業(yè)網(wǎng)站建設(shè)百度百科搜索入口
  • wordpress快速登錄插件真人seo點(diǎn)擊平臺(tái)
  • 方城企業(yè)網(wǎng)站制作哪家好英語(yǔ)培訓(xùn)
  • 個(gè)性化營(yíng)銷(xiāo)關(guān)鍵詞優(yōu)化資訊
  • 青島信息網(wǎng)官網(wǎng)保定網(wǎng)站建設(shè)方案優(yōu)化
  • 和田哪里有做網(wǎng)站的地方學(xué)網(wǎng)絡(luò)營(yíng)銷(xiāo)好就業(yè)嗎
  • 網(wǎng)站平臺(tái)開(kāi)發(fā)互聯(lián)網(wǎng)營(yíng)銷(xiāo)師證書(shū)有用嗎
  • 佛山網(wǎng)頁(yè)制作設(shè)計(jì)廣州seo軟件
  • 專(zhuān)業(yè)的網(wǎng)站建設(shè)哪家快業(yè)務(wù)員用什么軟件找客戶(hù)
  • 深度網(wǎng)網(wǎng)站建設(shè)方案寧波網(wǎng)站seo哪家好
  • 中小企業(yè)的網(wǎng)站建設(shè)論文今天國(guó)際新聞大事
  • 荔灣網(wǎng)站建設(shè)公司網(wǎng)頁(yè)制作軟件下載
  • 還有哪些網(wǎng)站做產(chǎn)品眾籌淘寶美工培訓(xùn)推薦
  • 開(kāi)發(fā)建設(shè)網(wǎng)站的實(shí)施過(guò)程是一個(gè)全球最大的中文搜索引擎
  • 工業(yè)設(shè)計(jì)研究生院校排名seo系統(tǒng)源碼出售
  • 做品牌網(wǎng)站的企業(yè)徐州關(guān)鍵詞優(yōu)化排名
  • 公益事業(yè)做網(wǎng)站網(wǎng)站流量查詢(xún)站長(zhǎng)之家
  • 網(wǎng)站建設(shè)幾種語(yǔ)言對(duì)比免費(fèi)加精準(zhǔn)客源
  • 一起做網(wǎng)站鄭州電商網(wǎng)站入口
  • 如何對(duì)網(wǎng)站的圖片做cdn萬(wàn)網(wǎng)創(chuàng)始人
  • 做我網(wǎng)站最近發(fā)生的熱點(diǎn)新聞事件
  • 什么是單頁(yè)網(wǎng)站西安網(wǎng)絡(luò)推廣外包公司
  • 網(wǎng)站服務(wù)合同用交印花稅嗎點(diǎn)擊器 百度網(wǎng)盤(pán)
  • 濟(jì)寧網(wǎng)站建設(shè)優(yōu)化百度網(wǎng)盤(pán)登錄入口 網(wǎng)頁(yè)
  • 把html文件生成網(wǎng)址平原縣網(wǎng)站seo優(yōu)化排名
  • 網(wǎng)頁(yè)設(shè)計(jì)實(shí)訓(xùn)總結(jié)2500字seo網(wǎng)站推廣案例
  • 諸城營(yíng)銷(xiāo)型網(wǎng)站建設(shè)seo自動(dòng)優(yōu)化工具
  • 中國(guó)空間站科幻作文1000字中國(guó)突然宣布一重磅消息
  • 網(wǎng)頁(yè)設(shè)計(jì)與網(wǎng)站建設(shè)作業(yè)怎么做周口seo公司
  • 東莞專(zhuān)業(yè)做網(wǎng)站建設(shè)服務(wù)怎么做百度推廣運(yùn)營(yíng)