一、Redisson是什么
Redisson 是一個基于 Redis 實現的 Java 駐內存數據網格(In-Memory Data Grid)。它不僅提供了一系列分布式和可擴展的 Java 數據結構,還對 Redis 進行了封裝,讓開發者可以更便捷地使用 Redis。
二、Redisson作用
- 簡化 Redis 操作:Redisson 為 Java 開發者提供了一套直觀且易于使用的 API,能把 Redis 當作普通的 Java對象或集合來操作,從而減少了與 Redis 交互時的復雜度。例如,你可以像操作 Java 的Map一樣操作 Redis 中的哈希表。
- 分布式鎖和同步機制:Redisson實現了多種分布式鎖和同步工具,如可重入鎖、公平鎖、讀寫鎖等,能確保在分布式環境下多個節點之間的數據一致性和并發控制。
- 豐富的數據結構:它提供了分布式的Map、List、Set、Queue等數據結構,這些結構在分布式系統中能被多個節點共享和操作。
- 異步和反應式編程支持:Redisson 支持異步和反應式編程模型,可提升應用程序的性能和響應能力。
三、使用場景
- 分布式鎖:在分布式系統中,多個服務可能會同時訪問和修改共享資源,使用 Redisson 的分布式鎖可以保證同一時間只有一個服務能夠操作該資源,避免數據沖突。例如,在電商系統中,多個訂單服務可能同時處理庫存扣減的操作,使用分布式鎖可以確保庫存數據的準確性。
- 分布式集合:當需要在多個服務之間共享數據時,可以使用 Redisson的分布式集合。比如,在一個分布式的消息系統中,多個消費者服務可以通過分布式隊列來處理消息。
- 分布式緩存:利用 Redisson 的分布式Map可以實現分布式緩存,將經常訪問的數據存儲在 Redis 中,減少數據庫的訪問壓力,提高系統的性能。例如,在一個高并發的 Web 應用中,可以將用戶的基本信息緩存在 Redis 中,當用戶訪問時直接從緩存中獲取數據。
- 分布式信號量:在分布式系統中,信號量可用于控制對有限資源的訪問。例如,在一個分布式的文件上傳系統中,可以使用信號量來限制同時上傳的文件數量。
四、使用
1、引入依賴:
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>${redisson.version}</version> <!--版本號根據項目適配-->
</dependency>
3、配置文件
# 數據源配置
spring:# redis 配置redis:# 地址host: 127.0.0.1# 端口,默認為6379port: 6379# 數據庫索引database: 5# 密碼password: # 連接超時時間timeout: 60slettuce:pool:# 連接池中的最小空閑連接min-idle: 0# 連接池中的最大空閑連接max-idle: 8# 連接池的最大數據庫連接數max-active: 8# #連接池最大阻塞等待時間(使用負值表示沒有限制)max-wait: -1ms
3、配置類:
@Component
@RefreshScope
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String password;@Value("${spring.redis.database}")private Integer database;@Beanpublic RedissonClient redissonClient() {// 創建配置 指定redis地址及節點信息Config config = new Config();//單例模式config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password) // redis設置了密碼,就需設置.setDatabase(database);// 根據config創建出RedissonClient實例并返回return Redisson.create(config);}
}
4、工具
@Slf4j
@Component
public class RedissonLock {@Resourceprivate RedissonClient redissonClient;/*** lock(), 拿不到lock就不罷休,不然線程就一直block*/public RLock lock(String key) {if (StringUtils.isBlank(key)) {return null;}RLock lock = redissonClient.getLock(key);try {lock = redissonClient.getLock(key);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** leaseTime為加鎖時間,單位為秒* @param key key* @param leaseTime 為加鎖時間,單位為秒*/public RLock lock(String key, long leaseTime) {if (StringUtils.isBlank(key) || leaseTime <= 0) {return null;}RLock lock = redissonClient.getLock(key);try {lock.lock(leaseTime, TimeUnit.SECONDS);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** timeout為加鎖時間,時間單位由unit確定*/public RLock lock(String key, TimeUnit unit, long timeout) {if (StringUtils.isBlank(key) || timeout <= 0 || unit == null) {return null;}RLock lock = redissonClient.getLock(key);try {lock.lock(timeout, unit);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** @param lockKey 鎖 key* @param unit 單位* @param waitTime 等待時間* @param leaseTime 鎖有效時間* @return 加鎖成功? true:成功 false: 失敗*/public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {RLock lock = redissonClient.getLock(lockKey);try {return lock.tryLock(waitTime, leaseTime, unit);} catch (InterruptedException e) {Thread.currentThread().interrupt();log.error("加鎖失敗: " + e.getMessage());return false;} catch (Exception e) {log.error("加鎖過程中發生異常: " + e.getMessage());return false;}}/*** unlock** @param lockKey key*/public void unlock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();}}/*** unlock** @param lock 鎖*/public void unlock(RLock lock) {lock.unlock();}
}
5、例子
@RestController
@Slf4j
public class RedissonController {@Resourceprivate RedissonLock redissonLock;@GetMapping("lockTest")public void lockTest(String key) {try {// 加鎖redissonLock.lock(key);System.out.println("獲取到鎖,開始執行任務");// 模擬業務操作Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 釋放鎖redissonLock.unlock(key);System.out.println("任務執行完畢,釋放鎖");}
}
總結
Lock和tryLock的區別