基于Redis分布式鎖Redisson及SpringBoot集成Redisson
- 分布式鎖需要具備的條件和剛需
- 獨(dú)占性:OnlyOne,任何時(shí)刻只能有且僅有一個(gè)線程持有
- 高可用:若redis集群環(huán)境下,不能因?yàn)槟骋粋€(gè)節(jié)點(diǎn)掛了而出現(xiàn)獲取鎖和釋放鎖失敗的情況
- 防死鎖:杜絕死鎖,必須有超時(shí)控制機(jī)制或者撤銷操作,有個(gè)兜底終止跳出方案
- 不亂搶:防止張冠李戴,不能私下unlock別人的鎖,只能自己加鎖自己釋放
- 重入性:同一個(gè)節(jié)點(diǎn)的同一個(gè)線程如果獲得鎖之后,它也可以再次獲取這個(gè)鎖
- Redisson使用
引入 redisson 依賴:
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.16.2</version> </dependency>
添加 redisson 配置:
import org.redisson.Redisson; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.io.Serializable; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); // 設(shè)置key序列號(hào)方式string redisTemplate.setKeySerializer(new StringRedisSerializer()); // 設(shè)置value的序列化方式j(luò)son redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public Redisson redisson() { Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.10.233:6379").setDatabase(0); return (Redisson) Redisson.create(config); } }
接口測(cè)試:
import org.redisson.Redisson; import org.redisson.api.RLock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private Redisson redisson; private static final String KEY = "spike"; @GetMapping("/buy") public String bugGood() { RLock redissonLock = redisson.getLock(KEY); redissonLock.lock(); try { String result = stringRedisTemplate.opsForValue().get("goods:001"); int goodNumber = result == null ? 0 : Integer.parseInt(result); if (goodNumber > 0) { int realNum = goodNumber - 1; stringRedisTemplate.opsForValue().set("goods:001", realNum + ""); return "秒殺成功,剩余庫(kù)存:" + realNum; } return "商品已售罄!"; } finally { redissonLock.unlock(); } } }
多節(jié)點(diǎn)的情況下,代碼相同,要保證 lock 的 key 一樣
- SpringBoot集成Redisson
引入 redis 和 redisson starter:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> </dependency>
redis 配置:
spring: redis: # 地址 host: 192.168.20.26 # 端口,默認(rèn)為6379 port: 6379 password: 123456 # 連接超時(shí)時(shí)間 timeout: 30s database: 0 lettuce: pool: # 連接池中的最小空閑連接 min-idle: 0 # 連接池中的最大空閑連接 max-idle: 8 # 連接池的最大數(shù)據(jù)庫(kù)連接數(shù) max-active: 8 # #連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) max-wait: -1ms
redisson配置:
import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.redisson.config.SingleServerConfig; import org.redisson.config.TransportMode; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * redisson配置 */ @Configuration public class RedissonConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private String port; @Value("${spring.redis.password}") private String password; @Bean public RedissonClient redissonClient() { Config config = new Config(); config.setTransportMode(TransportMode.NIO); // 單體配置,如果是SSL連接,使用 rediss:// SingleServerConfig singleServerConfig = config.useSingleServer(); singleServerConfig.setAddress("redis://" + host + ":" + port); singleServerConfig.setPassword(password); return Redisson.create(config); } }
使用:
import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; public class TestController { @Resource private RedissonClient redissonClient; public void doAction1() { String lockKey = "lockKey"; RLock lock = redissonClient.getLock(lockKey); // 加鎖,無(wú)參數(shù) lock.lock(); // 鎖有效時(shí)間,時(shí)間單位 // lock.lock(5, TimeUnit.SECONDS); try { // do something } finally { // 解鎖 lock.unlock(); } } public void doAction2() throws InterruptedException { String lockKey = "lockKey"; RLock lock = redissonClient.getLock(lockKey); // 1. 無(wú)參數(shù),直接上鎖 // lock.tryLock(); // 2. 等待時(shí)間,時(shí)間單位 // lock.tryLock(3, TimeUnit.SECONDS); // 3. 等待時(shí)間,鎖有效時(shí)間,時(shí)間單位 // lock.tryLock(3, 5, TimeUnit.SECONDS); try { // 常規(guī)寫(xiě)法 if (lock.tryLock(3, 5, TimeUnit.SECONDS)) { // do something } else { // 沒(méi)有獲取到鎖 } } finally { // 解鎖 lock.unlock(); } } }
到此這篇關(guān)于基于Redis分布式鎖Redisson及SpringBoot集成Redisson的文章就介紹到這了,更多相關(guān)Redis分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java操作minio刪除文件夾及其文件方法(MinIO基本使用)
MinIO是一個(gè)高性能、無(wú)限擴(kuò)展的開(kāi)源對(duì)象存儲(chǔ)服務(wù)器,它以對(duì)象的形式存儲(chǔ)數(shù)據(jù),并兼容Amazon S3接口,它適用于大規(guī)模數(shù)據(jù)存儲(chǔ)、大數(shù)據(jù)分析、文件共享和備份等應(yīng)用場(chǎng)景,這篇文章主要介紹了java操作minio刪除文件夾及其文件方法,需要的朋友可以參考下2024-02-02詳解Eclipse Validating緩慢的優(yōu)化
這篇文章主要介紹了詳解Eclipse Validating緩慢的優(yōu)化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03SpringBoot項(xiàng)目中忽略某屬性返回?cái)?shù)據(jù)給前端
在Spring Boot中,保護(hù)敏感信息和減少數(shù)據(jù)傳輸是很重要的,我們可以使用多種方法來(lái)忽略返回?cái)?shù)據(jù)中的字段,無(wú)論是使用@JsonIgnore注解、Projection投影、@JsonIgnoreProperties注解還是自定義序列化器,都能達(dá)到我們的目的,在實(shí)際應(yīng)用中,根據(jù)具體場(chǎng)景和需求選擇合適的方法2024-05-05MyBatis在insert插入操作時(shí)返回主鍵ID的配置(推薦)
這篇文章主要介紹了MyBatis在insert插入操作時(shí)返回主鍵ID的配置的相關(guān)資料,需要的朋友可以參考下2017-10-10spring注解識(shí)別一個(gè)接口的多個(gè)實(shí)現(xiàn)類方法
下面小編就為大家?guī)?lái)一篇spring注解識(shí)別一個(gè)接口的多個(gè)實(shí)現(xiàn)類方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Spring Boot集成Quartz注入Spring管理的類的方法
本篇文章主要介紹了Spring Boot集成Quartz注入Spring管理的類的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Java經(jīng)典算法匯總之選擇排序(SelectionSort)
選擇排序也是比較簡(jiǎn)單的一種排序方法,原理也比較容易理解,選擇排序在每次遍歷過(guò)程中只記錄下來(lái)最小的一個(gè)元素的下標(biāo),待全部比較結(jié)束之后,將最小的元素與未排序的那部分序列的最前面一個(gè)元素交換,這樣就降低了交換的次數(shù),提高了排序效率。2016-04-04