基于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 "秒殺成功,剩余庫存:" + 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ù)庫連接數(shù)
max-active: 8
# #連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
max-wait: -1msredisson配置:
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);
// 加鎖,無參數(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. 無參數(shù),直接上鎖
// lock.tryLock();
// 2. 等待時(shí)間,時(shí)間單位
// lock.tryLock(3, TimeUnit.SECONDS);
// 3. 等待時(shí)間,鎖有效時(shí)間,時(shí)間單位
// lock.tryLock(3, 5, TimeUnit.SECONDS);
try {
// 常規(guī)寫法
if (lock.tryLock(3, 5, TimeUnit.SECONDS)) {
// do something
} else {
// 沒有獲取到鎖
}
} 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è)高性能、無限擴(kuò)展的開源對(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)化,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
SpringBoot項(xiàng)目中忽略某屬性返回?cái)?shù)據(jù)給前端
在Spring Boot中,保護(hù)敏感信息和減少數(shù)據(jù)傳輸是很重要的,我們可以使用多種方法來忽略返回?cái)?shù)據(jù)中的字段,無論是使用@JsonIgnore注解、Projection投影、@JsonIgnoreProperties注解還是自定義序列化器,都能達(dá)到我們的目的,在實(shí)際應(yīng)用中,根據(jù)具體場(chǎng)景和需求選擇合適的方法2024-05-05
MyBatis在insert插入操作時(shí)返回主鍵ID的配置(推薦)
這篇文章主要介紹了MyBatis在insert插入操作時(shí)返回主鍵ID的配置的相關(guān)資料,需要的朋友可以參考下2017-10-10
spring注解識(shí)別一個(gè)接口的多個(gè)實(shí)現(xiàn)類方法
下面小編就為大家?guī)硪黄猻pring注解識(shí)別一個(gè)接口的多個(gè)實(shí)現(xiàn)類方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
Spring Boot集成Quartz注入Spring管理的類的方法
本篇文章主要介紹了Spring Boot集成Quartz注入Spring管理的類的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04
Java經(jīng)典算法匯總之選擇排序(SelectionSort)
選擇排序也是比較簡(jiǎn)單的一種排序方法,原理也比較容易理解,選擇排序在每次遍歷過程中只記錄下來最小的一個(gè)元素的下標(biāo),待全部比較結(jié)束之后,將最小的元素與未排序的那部分序列的最前面一個(gè)元素交換,這樣就降低了交換的次數(shù),提高了排序效率。2016-04-04

