基于Redisson框架实现redis分布式锁
1、起初
引入依赖
1
2
3
4
5
|
<!-- spring boot redis缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> |
controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/** * @author lj on 2021/2/28. * @version 1.0 */ public class IndexController { @Autowired private StringRedisTemplate redisTemplate; @RequestMapping ( "/test" ) public String testRedisDis(){ final Boolean res = redisTemplate.opsForValue().setIfAbsent( "lock_key" , "liujun" ); if (!res){ return "error" ; } /** * 执行代码业务 */ return "end" ; } } |
思考?带来一系列的问题:
1、系统宕机,未释放锁即死锁(redis设置过期时间,增加try...finally...代码段)
2、业务时间太长,释放别人的锁(设置redis值为唯一uuid;在释放锁时(redisTemplate.delete("key"),增加逻辑判断只能释放自己的锁);增加看门狗来续时)
3、保证redis操作的原子性(redis设置值和设置过期时间必须同步)
2、进一步优化:
controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/** * @author lj on 2021/2/28. * @version 1.0 */ public class IndexController { @Autowired private StringRedisTemplate redisTemplate; @RequestMapping ( "/test" ) public String testRedisDis(){ String lock_key = "prodect_001" ; final String vaule = UUID.randomUUID().toString(); try { final Boolean res = redisTemplate.opsForValue().setIfAbsent(lock_key, vaule, 30 , TimeUnit.SECONDS); //保证redis的原子性,设置时长防止redis死锁 if (!res){ return "error" ; } //TODO 开辟一个分线程使用定时器进行redis续时 /** * 执行代码业务 */ } finally { //释放锁 if (vaule.equals(redisTemplate.opsForValue().get(lock_key))){ //防止释放别人的锁 redisTemplate.delete( "lock_key" ); } return "end" ; } } } |
3、使用Redisson框架
1、引入Redisson的依赖
1
2
3
4
5
|
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version> 3.6 . 5 </version> </dependency> |
2、配置为单机模式
1
2
3
4
5
6
7
|
@Bean public Redisson redisson(){ //此为单机模式 final Config config = new Config(); config.useSingleServer().setAddress( "127.0.0.1:6379" ).setDatabase( 0 ); return (Redisson) Redisson.create(config); } |
3、简单的使用代码片段
整个流程:
watch dog自动延期机制
客户端1加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?
简单!只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。
如果时集群的话还有一个问题:就是redis的master节点宕机了,而锁没来得及复制到slave节点(待处理。。。)
总结:redisson框架其实就是上面redis过程的优化;
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放;抢到锁后会开辟一个分线程看门狗去续时,最后在finally代码快中删除锁。