Redisson實現分散式鎖
阿新 • • 發佈:2018-12-06
Redisson文件參考:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95
開始引入
pom檔案中引入依賴:
<!-- redisson 分散式鎖實現 --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.8.2</version> </dependency>
spring中配置:
引入約束:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://redisson.org/schema/redissonhttp://redisson.org/schema/redisson/redisson.xsd" default-lazy-init="true">
測試staging環境:
<!-- redisson 客戶端 配置實現 --> <redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6600"/> <redisson:node-address value="redis://127.0.0.1:6601"/> <redisson:node-address value="redis://127.0.0.1:6602"/> </redisson:cluster-servers> </redisson:client>
生產production環境:
<!-- redisson 客戶端 配置實現 --> <redisson:client id="redissonClient"> <redisson:cluster-servers password="${password}"> <redisson:node-address value="redis://127.0.0.1:6602"/> <redisson:node-address value="redis://127.0.0.1:6603"/> <redisson:node-address value="redis://127.0.0.2:6602"/> <redisson:node-address value="redis://127.0.0.2:6603"/> <redisson:node-address value="redis://127.0.0.3:6602"/> <redisson:node-address value="redis://127.0.0.3:6603"/> </redisson:cluster-servers> </redisson:client>
業務中使用:
public class LockBiz { @Autowired RedissonClient redissonClient; public boolean doWithLock(long groupId, OperateType operateType, String operator, List<Config> configList) { boolean isLocked = false; String lockName = "fi_config_groupid_" + groupId; RLock lock = redissonClient.getLock(lockName); if (lock == null) { log.error("lock is null"); return false; } try { try { boolean lockedState = lock.isLocked(); if (lockedState) { log.error("lock_redisson state seems already locked: {}, name of lock is: {}", lockedState, lockName); } for (int i = 0; i < Constants.TRY_TIMES; ++i) { isLocked = lock.tryLock(Constants.TRY_LOCK_TIME, Constants.AUTO_UNLOCK_TIMES, Constants.LOCK_TIME_UNIT); log.info("lock_redisson result: {}, try times: {}, time consuming: {}", isLocked, (i+1), (System.currentTimeMillis() - startLock)); if (isLocked) { break; } } } catch (InterruptedException e) { log.error("failed to get lock_redisson: ", e); } if (!isLocked) { log.error("try lock_redisson failed"); } /** 加鎖成功,處理業務邏輯 */ } finally { if (isLocked) { try { lock.unlock(); } catch (Throwable t) { log.error("failed to unlock_redisson, {}", ExceptionUtils.getStackTrace(t)); } } } } }
注意事項:
1. redisson的2版本和3版本在配置redis地址的時候貌似不一致,2版本無需字首“redis://”,而3版本需要;
2. getLock時,RLock lock = redissonClient.getLock(lockName); 這個lockName一定要唯一,redisson應該是將這個lockName同時作為lock的name和key的名稱,如果和別人重複了,就需要和別人競爭同一把鎖了,而不是自己的業務和自己的業務競爭鎖了。(今天就出現了個問題,我把lockName設定為2,經常會出現加鎖失敗,並且是在迴圈加鎖之前 這把鎖就已經鎖上了,現在想想應該是別人在其他地方給redis中添加了個key=2的,導致我無法加鎖,排查了挺長時間)