当前位置:网站首页>分布式锁解决方案之Redis实现
分布式锁解决方案之Redis实现
2022-07-26 10:28:00 【范学博】
spring boot 版本 2.1.6.RELEASE
下面是分布式锁的获取和释放,成员变量:StringRedisTemplate(springboot整合redis获取redis,也可通过注入jedis实现,实现思路是一致的,我会在文末附上获取redis的实现)。
再来看看一些redis的基本命令: SETNX key value (stringRedisTemplate.opsForValue().setIfAbsent())
如果key不存在,就设置key对应字符串value。在这种情况下,该命令和SET一样。当key已经存在时,就不做任何操作。SETNX是”SET if Not eXists”。 expire KEY seconds (stringRedisTemplate.expire())
设置key的过期时间。如果key已过期,将会被自动删除。 del KEY (stringRedisTemplate.delete())
删除key
分布式锁的获取与释放
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @author fanxuebo
* @description 分布式锁
* @company
* @create 2019/1/10 17:48
*/
public class DistributedLock {
private static final Logger LOGGER = LoggerFactory.getLogger(DistributedLock.class);
private StringRedisTemplate stringRedisTemplate;
public DistributedLock(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* @Author fanxuebo
* @Date 2019/1/11 10:10
* @Description 获取锁,锁的名称,获取锁超时时间,释放锁的超时时间
**/
public String lockWithTimeout(String lockName, long timeout) {
String retIdentifier = null;
try {
String identifier = UUID.randomUUID().toString();// 随机生成一个value
String lockKey = "lock:" + lockName;// 锁名,即key值
int lockExpire = (int) (timeout / 1000);// 超时时间,上锁后超过此时间则自动释放锁
while (true) {
if (stringRedisTemplate.opsForValue().setIfAbsent(lockKey, identifier)) {
LOGGER.info("{}:获取到锁lockKey:{}", Thread.currentThread().getName(), lockKey);
stringRedisTemplate.expire(lockKey, lockExpire, TimeUnit.SECONDS);
retIdentifier = identifier;// 返回value值,用于释放锁时间确认
break;
}
// 返回-1代表key没有设置超时时间,为key设置一个超时时间
if (stringRedisTemplate.getExpire(lockKey) == -1L) {
stringRedisTemplate.expire(lockKey, lockExpire, TimeUnit.SECONDS);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("获取锁异常:[{}]", e.getStackTrace()[0]);
}
return retIdentifier;
}
/**
* @Author fanxuebo
* @Date 2019/1/11 10:09
* @Description 释放锁
**/
public boolean releaseLock(String lockName, String identifier) {
String lockKey = "lock:" + lockName;
boolean retFlag = false;
try {
while (true) {
stringRedisTemplate.watch(lockKey);// 监视lock,准备开始事务
// 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁
if (identifier.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
LOGGER.info("{}:删除锁lockKey:{}", Thread.currentThread().getName(), lockKey);
stringRedisTemplate.delete(lockKey);
retFlag = true;
}
stringRedisTemplate.unwatch();
break;
}
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("释放锁异常:[{}]", e.getStackTrace()[0]);
}
return retFlag;
}
}在需要上锁的代码块只需做如下操作:
DistributedLock distributedLock = new DistributedLock(stringRedisTemplate);
String lockName = XXX;
String identifier = null;
try {
identifier = distributedLock.lockWithTimeout(lockName, 3000);
//需要控制事务的代码
distributedLock.releaseLock(lockName, identifier);
} catch (Exception e) {
distributedLock.releaseLock(lockName, identifier);
}在获取锁方法处可做改进,传入获取锁的时间,在一定时间内获取,若未获取到返回的标识为NULL。
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {}DistributedLock distributedLock = new DistributedLock(stringRedisTemplate);
String lockName = XXX;
String identifier = null;
try {
identifier = distributedLock.lockWithTimeout(lockName, 3000);
if (StringUtils.isBlank(identifier)) {
//获取锁等待超时的处理
}
//需要控制事务的代码
distributedLock.releaseLock(lockName, identifier);
} catch (Exception e) {
distributedLock.releaseLock(lockName, identifier);
}
springboot整合reids:
<!-- 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>
<!-- <version>2.1.6.RELEASE</version> -->
</dependency>import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author fanxuebo
* @description redis配置类
* @company
* @createDate 2019-11-27 08:46:17 星期三
*/
@Configuration
public class RedisConfiguration {
/**
* @Author fanxuebo
* @Date 2019/11/27 9:05
* @Description jdk序列方式,用来保存对象
**/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
return getRedisTemplate(redisTemplate, redisConnectionFactory);
}
/**
* @Author fanxuebo
* @Date 2019/11/27 9:06
* @Description string序列方式,用于存储字符串格式
**/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
return (StringRedisTemplate) getRedisTemplate(stringRedisTemplate, redisConnectionFactory);
}
private RedisTemplate getRedisTemplate(RedisTemplate redisTemplate, RedisConnectionFactory redisConnectionFactory) {
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
配置文件:
spring:
redis:
database:
host:
port: 6379
password:
timeout: 5000
jedis:
pool:
max-active: 50
max-wait: 5000希望阅读后会让你们有所收获,本文待完善。。。
边栏推荐
- Some cutting-edge research work sharing of SAP ABAP NetWeaver containerization
- Reproduce the snake game in C language (I) build pages and construct snakes
- equals与==的区别
- Network related journals and conferences in CS
- 【Halcon视觉】图像滤波
- Cause: could't make a guess for solution
- 将json文件中数组转换为struct
- Mlx90640 infrared thermal imager temperature sensor module development notes (6)
- 关于函数模板描述错误的是(链接格式错误怎么解决)
- 抓包工具fiddler和wireshark对比
猜你喜欢

The charm of SQL optimization! From 30248s to 0.001s

数据库的复习--1.概述

Introduction to latex, EPS picture bounding box

Employee information management system based on Web
![[Halcon vision] array](/img/29/905d93795a24538fded18d2d377e52.png)
[Halcon vision] array

videojs转canvas暂停、播放、切换视频
![[Qualcomm][Network] qti服务分析](/img/76/49054ff8c7215eca98cc479ab1d986.png)
[Qualcomm][Network] qti服务分析

如何写一篇百万阅读量的文章

Study on the basis of opencv

Dynamically determine file types through links
随机推荐
Data communication foundation STP principle
The charm of SQL optimization! From 30248s to 0.001s
Learning about opencv (3)
js下载文件,FileSaver.js导出txt、excel文件
【Halcon视觉】算子的结构
[socket] the three handshakes are completed in listen, and accept only takes out one connection from the queue that completes the connection
议程速递 | 7月27日分论坛议程一览
Using undertow, Nacos offline logout delay after service stop
404页面和路由钩子
Reproduce the snake game in C language (I) build pages and construct snakes
数据库的复习--1.概述
json_object_put: Assertion `jso->_ref_count > 0‘ failed.Aborted (core dumped)
Prevent XSS attacks
Mlx90640 infrared thermal imager temperature sensor module development notes (6)
mysql 进不去了怎么办
The problem of four columns of Hanoi Tower
js 获得当前时间,时间与时间戳的转换
面试第二家公司的面试题及答案(二)
On the compilation of student management system of C language course (simple version)
[Halcon vision] array