1.場景還原
在併發的場景,分佈式鎖是一種比較常規且實用的解決方案;今天筆者就springboot中如何實現redis分佈式鎖作個講解
2.關注點
實現redis分佈式鎖的關鍵在於設置儲存值與過期時間要保證是一個原子性操作,否則會發生死鎖
3.實現方案
1、pom依賴
<!--集成redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、redis鎖實現
/**
* @auther xxx
* @date 2018/7/21 10:23
*
* redis 分佈式鎖 加鎖與解密配套使用
*/
@Component
@Slf4j
public class RedisLock {
@Autowired
private HashRedisTemplate stringRedisTemplate;
/**
* 加鎖
* @param key 鎖唯一標誌
* @param timeout 超時時間
* @return
*/
public boolean lock(String key, long timeout){
String value = String.valueOf(timeout + System.currentTimeMillis());
if(stringRedisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
//判斷鎖超時,防止死鎖
String currentValue = (String)stringRedisTemplate.opsForValue().get(key);
//如果鎖過期
if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){
//獲取上一個鎖的時間value
String oldValue = (String) stringRedisTemplate.opsForValue().getAndSet(key,value);
if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue) ){
//校驗是不是上個對應的商品時間戳,也是防止併發
return true;
}
}
return false;
}
/**
* 解鎖
* @param key
* @param value
*/
public void unlock(String key,String value){
try {
String currentValue = (String) stringRedisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value) ){
stringRedisTemplate.opsForValue().getOperations().delete(key);//刪除key
}
} catch (Exception e) {
log.error("[Redis分佈式鎖] 解鎖出現異常了,{}",e);
}
}
}