当前位置:网站首页>利用redis实现分布式锁(单个redis)
利用redis实现分布式锁(单个redis)
2022-07-23 07:43:00 【禹哥。。。】
因为redis是单线程程序,可以天然保证线程安全,只要我们的命令是单条命令,就可以保证操作的安全性,而redis中提供了setnx key value命令,表示当redis中没有key 的键值对时,就会创建这个键值对的值,如果已经有了,就不操作,java中有valueOperations.setIfAbsent(key,value)与redis中的setnx是一样的作用。我们可以使用valueOperations.setIfAbsent实现分布式加锁的操作,也可以给锁设置过期时间,这样就算客户端故障也能在过期时间之后释放锁
Boolean isLock=valueOperations.setIfAbsent("k1",value,120,TimeUnit.SECONDS);
key是任意值,value保证每个使用者唯一性即可,便于锁的释放,因为我们在释放锁也就是del key时,需要保证只有真正获得锁的程序才能去释放对应的锁,而不是谁都可以进行锁的释放,防止自己获得锁被别人释放了,所以我们释放锁的步骤就是:
- 先判断锁变量的值,是否是自己获得锁
- 如果是自己获取的锁,就可以进行锁的释放
- 如果不是自己获取的锁,就无法进行锁的释放
这就不是一个命令了,但是我们需要这些命令原子性执行,所以就用到了lua脚本。Redis对lua脚本的调用是原子性的,所以一些特殊场景,可以放在lua中实现,这里记录下来一个简单的例子
首先在resources目录下创建一个lock.lua文件
if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
当输入的key[1]在redis中等于输入的argv[1]时,删除这个原有的key,即释放锁,不等则无法释放锁 key[1]:获取锁时输入的key,argv[1]:获取锁时输入的value
@Test
public void testLock03() {
ValueOperations valueOperations=redisTemplate.opsForValue();
String value= UUID.randomUUID().toString();
//如果key为空,就设置值
Boolean isLock=valueOperations.setIfAbsent("k1",value,120,TimeUnit.SECONDS);
if(isLock) {
valueOperations.set("name","xxxx");
String name=(String)valueOperations.get("name");
System.out.println("name="+name);
System.out.println(valueOperations.get("k1"));
Boolean result=(Boolean)redisTemplate.execute(script, Collections.singletonList("k1"),value);
System.out.println(result);
}
else {
System.out.println("有线程在使用,请稍后");
}
}
其中singletonList是一个不可变list,且只有一个元素,就是从redis拿k1对应的value,看与方法传进去的value一样不一样,一样的话就是直接key(释放锁)。
redisConfig类
//将信息序列化,在redis中看起来好看
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//key的序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
//value的序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//hash类型key的序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//hash类型value的序列化
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
//注入连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
@Bean
public DefaultRedisScript<Boolean> script() {
DefaultRedisScript<Boolean> redisScript=new DefaultRedisScript<>();
redisScript.setLocation(new ClassPathResource("lock.lua"));
redisScript.setResultType(Boolean.class);
return redisScript;
}
}
边栏推荐
- 静态综合实验(HCIA)
- APP常用跨端技术栈深入分析
- Warcraft map editor trigger notes
- 图像处理3:Sobel边缘检测
- 做测试如何应对新的开发模式?
- Kingbaseesv8r6 difference of xmin under different isolation levels
- 容器网络原理
- OSPF experiment in mGRE environment:
- 解决报错:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: “
- LeetCode_47_全排列Ⅱ
猜你喜欢
随机推荐
KingbaseESV8R6不同隔离级下xmin的区别
KingbaseES DENSE_RANK 函数用法
Warcraft map editor trigger notes
LeetCode_51_N皇后
Thousands of databases, physical machines all over the country, JD logistics full volume cloud live record | interview with excellent technical team
MGRE experiment
-20: +usecgroupmemorylimitforheap failed to create virtual machine problem
容器网络原理
How to ensure the reliable transmission of messages? What if the message is lost
LeetCode_ 52_ Queen n II
Connaissance détaillée du GRE, du mgre; Connaissance de la configuration de base de l'OSPF
Événements courants de la souris et du clavier
C #: in, out, ref Keywords
LeetCode_ 47_ Full arrangement II
数千个数据库、遍布全国的物理机,京东物流全量上云实录 | 卓越技术团队访谈录
C#:in、out、ref關鍵字
Talking about the CPU type of anroid device and the placement directory of so files
第四次作业
常用的鼠标事件和键盘事件
数据链路层协议,PPP会话









