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代碼快中刪除鎖。