1、起初
引入依赖
<!-- spring boot redis缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
controller层
/** * @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层
/** * @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的依赖
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.6.5</version> </dependency>
2、配置为单机模式
@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代码快中删除锁。