分散式鎖(五)——基於redisson的分散式鎖例項
阿新 • • 發佈:2020-01-30
Redisson簡介
Redisson是一個在Redis的基礎上實現的Java駐記憶體資料網格(In-Memory Data Grid)。它不僅提供了一系列的分散式的Java常用物件,還提供了許多分散式服務。redisson參考文件。一定程度上他豐富了redis的資料型別 ,同時底層採用NIO的網路互動方式,進一步提升了分散式協調的相關能力。
更多關於Redisson的內容可以參見上述貼出的文件地址。Redisson實現分散式鎖相比redis就方便了許多。
springboot中引入Redisson
1、引入redisson的配置
spring.redisson.address=redis://127.0.0.1:6379
配置需要以redis開頭,畢竟在redisson的create原始碼中有這一段
public static URI create(String uri) { URI u = URI.create(uri); // Let's assuming most of the time it is OK. if (u.getHost() != null) { return u; } String s = uri.substring(0,uri.lastIndexOf(":")).replaceFirst("redis://","").replaceFirst("rediss://",""); // Assuming this is an IPv6 format,other situations will be handled by // Netty at a later stage. return URI.create(uri.replace(s,"[" + s + "]")); }
很明顯的看到這裡的字串處理的時候,會切割掉redis開頭或者rediss開頭,如果沒有則會丟擲異常。
2、將redisson交給容器管理
/** * redisson的分散式客戶端 * @return */ @Bean public RedissonClient redissonClient(){ Config config = new Config(); config.useSingleServer().setAddress(env.getProperty("spring.redisson.address")); RedissonClient client = Redisson.create(config); return client; }
將這個bean交給有configuration註解的類進行託管。並返回RedissonClient(其實可以直接返回Redisson)
引入redisson,封裝各種操作
package com.learn.lockservce.component;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* autor:liman
* createtime:2020/1/30
* comment: Redisson的分散式鎖元件。
*/
@Component
@Slf4j
public class RedissonLockComponent implements InitializingBean {
@Autowired
private RedissonClient redissonClient;
private static Redisson redisson;
//注入後的屬性設定方法,這裡其實有點稍微多此一舉,可以直接在容器託管的時候就返回Redisson就行。
public void afterPropertiesSet() throws Exception {
redisson = (Redisson) redissonClient;
}
/**
* 獲取鎖
* @param lockName
* @return
*/
public RLock acquireLock(String lockName){
RLock lock = redisson.getLock(lockName);
lock.lock();
return lock;
}
/**
* 釋放鎖
* @param lock
*/
public void releaseLock(RLock lock){
lock.unlock();
}
}
這裡封裝了獲取鎖和釋放鎖的操作,同時通過實現InitializingBean介面中的afterProperties的方法,完成了型別的強行轉換。這裡再順帶提一下,原始碼中可以看到Redisson是RedissonClient的一種實現。
同樣的業務處理
/**
* 基於Redisson分散式鎖
* @param productLockDto
* @return
*/
@Transactional(rollbackFor = Exception.class)
public int updateStockRedisson(ProductLockDto productLockDto){
int res = 0;
boolean flag = true;
while(flag){
//獲取分散式鎖。
RLock rLock = redissonLockComponent.acquireLock(String.valueOf(productLockDto.getId()));
try{
if(rLock!=null){
//真正的業務處理
flag=false;
ProductLock productLockEntity = lockMapper.selectByPrimaryKey(productLockDto.getId());
int leftStock = productLockEntity.getStock();
if(productLockEntity!=null && productLockEntity.getStock().compareTo(productLockDto.getStock())>=0){
productLockEntity.setStock(productLockDto.getStock());
res = lockMapper.updateStockForNegative(productLockEntity);
if(res>0){
log.info("基於redisson獲取分散式鎖成功,剩餘stock:{}",leftStock-1);
}
}
}
}catch (Exception e){
//異常處理之後,繼續獲取鎖
log.error("獲取鎖異常,{}",e.fillInStackTrace());
flag=true;
}finally {
//正確釋放鎖
if(rLock!=null){
redissonLockComponent.releaseLock(rLock);
flag=false;
}
}
}
return res;
}
和之前幾篇部落格,一樣的業務邏輯,一樣的程式碼主體,一樣的思想,這裡就不總結了,似乎可以看出大體上都是這樣的輪子
/**
* 基於Redisson分散式鎖
* @param productLockDto
* @return
*/
@Transactional(rollbackFor = Exception.class)
public int updateStockRedisson(ProductLockDto productLockDto){
int res = 0;
boolean flag = true;
while(flag){
//獲取分散式鎖。
RLock rLock = redissonLockComponent.acquireLock(String.valueOf(productLockDto.getId()));
try{
if(rLock!=null){
//真正的業務處理
}
}catch (Exception e){
//異常處理之後,繼續獲取鎖
log.error("獲取鎖異常,{}",e.fillInStackTrace());
flag=true;
}finally {
//正確釋放鎖
}
}
return res;
}
總結
至此,關於幾種分散式鎖的簡單例項,總結完成,具體參見如下: