RedisTemplate和Redisson的區(qū)別
1、Redisson和RedisTemplate的什么區(qū)別

一、功能方面:
Redisson:
- 提供了豐富的分布式數(shù)據(jù)結構和服務,例如分布式鎖、分布式集合(包括分布式列表、集合、映射、隊列、阻塞隊列、雙端隊列、優(yōu)先隊列等)、分布式對象(如分布式對象、原子數(shù)、位圖等)以及分布式服務(如分布式遠程服務、分布式調度服務、分布式映射存儲等)。它對 Redis 的操作進行了高度抽象和封裝,極大地簡化了分布式系統(tǒng)的開發(fā)。例如,使用 Redisson 的分布式鎖可以這樣:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonExample {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 客戶端配置
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 在此執(zhí)行需要加鎖的代碼邏輯
System.out.println("執(zhí)行加鎖后的操作");
} finally {
// 解鎖
lock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
上述代碼首先創(chuàng)建了 Redisson 的配置對象,將 Redis 服務地址添加進去,接著創(chuàng)建 Redisson 客戶端。通過 getLock 方法獲取一個鎖對象,使用 lock 方法加鎖,執(zhí)行完操作后用 unlock 方法解鎖。這樣就實現(xiàn)了分布式鎖的操作,而且 Redisson 的鎖支持可重入、公平鎖等高級特性,能很好地處理分布式環(huán)境下的并發(fā)問題。
支持異步操作,可利用
RFuture接口來實現(xiàn)異步調用,提高系統(tǒng)的并發(fā)性能。例如,獲取鎖時可以使用lockAsync方法,后續(xù)可對RFuture進行相應處理,充分利用異步操作的優(yōu)勢。RedisTemplate:
- 主要是對 Redis 的基本數(shù)據(jù)結構(如字符串、哈希、列表、集合、有序集合)進行操作的模板類。它是 Spring Data Redis 中的一部分,更側重于對 Redis 基本操作的封裝,開發(fā)者需要根據(jù)不同的數(shù)據(jù)結構選擇不同的操作接口,操作相對更加底層。例如,使用 RedisTemplate 操作哈希表:
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.HashOperations;
public class RedisTemplateExample {
private RedisTemplate<String, Object> redisTemplate;
public void setHashValue() {
HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
hashOps.put("myHash", "key", "value");
}
}
這里先通過 opsForHash 方法獲取 HashOperations 接口,然后使用 put 方法將一個鍵值對放入哈希表中。其操作比較基礎,對于一些復雜的分布式場景,需要開發(fā)者自己去實現(xiàn)相應的邏輯。
二、性能方面:
Redisson:
- 因為提供了大量高級功能和封裝,可能會帶來一定的性能開銷,尤其是在一些復雜的分布式操作場景下。不過,對于需要這些高級功能的分布式系統(tǒng)開發(fā),它能節(jié)省大量開發(fā)時間和精力,且其性能對于大多數(shù)分布式場景是可以接受的。
- 對于異步操作,如果使用得當,可以提高系統(tǒng)的并發(fā)性能,避免同步等待,減少阻塞。
RedisTemplate:
- 相對而言,它的性能開銷可能較小,更適合一些對性能敏感且只需要使用 Redis 基本操作的簡單場景。
三、使用場景方面:
Redisson:
- 適用于開發(fā)分布式系統(tǒng),如分布式鎖在分布式事務、分布式任務調度、分布式緩存更新等場景中非常有用;分布式集合可用于分布式存儲和處理大量數(shù)據(jù);分布式服務可實現(xiàn)遠程調用、分布式執(zhí)行任務等。在需要大量使用 Redis 高級功能,如解決分布式環(huán)境中的并發(fā)問題、數(shù)據(jù)一致性問題、分布式服務調用等場景下表現(xiàn)出色。
RedisTemplate:
- 適合對 Redis 進行簡單操作的場景,例如簡單的緩存存儲和讀取、基本的數(shù)據(jù)結構操作等,更適合在 Spring 框架中使用,并且對于開發(fā)者想要對 Redis 操作有更多控制權,愿意自己實現(xiàn)一些高級功能邏輯的情況,使用 RedisTemplate 可以更好地進行自定義操作。
四、開發(fā)體驗方面:
Redisson:
- 開發(fā)體驗較好,代碼簡潔,很多分布式功能可以通過簡單的 API 調用實現(xiàn),大大減少了開發(fā)分布式功能的代碼量,降低了開發(fā)分布式系統(tǒng)的難度,提高了開發(fā)效率。
RedisTemplate:
- 對于熟悉 Spring 框架和 Spring Data Redis 的開發(fā)者來說,使用 RedisTemplate 比較順手,但在處理分布式復雜功能時,需要開發(fā)者深入 Redis 命令,自己實現(xiàn)相關邏輯,開發(fā)難度可能會相對較高。
五、社區(qū)和維護方面:
Redisson:
- 有自己獨立的社區(qū)和維護團隊,會持續(xù)更新和完善功能,對 Redis 新特性的支持也比較及時,并且在分布式領域有一定的技術積累,能為使用其的開發(fā)者提供技術支持和文檔。
RedisTemplate:
- 依托于 Spring 社區(qū),能隨著 Spring 框架的更新而更新,但在 Redis 分布式功能的擴展上可能相對依賴 Spring 官方的支持和社區(qū)貢獻,對于 Redis 自身高級功能的更新和支持可能不如 Redisson 及時。
綜上所述,Redisson 更適合開發(fā)復雜的分布式系統(tǒng),提供了很多高級的分布式解決方案,而 RedisTemplate 更適合簡單的 Redis 操作和希望對 Redis 操作有更多自定義的開發(fā)者。
2、Redisson實現(xiàn)分布式鎖
Redisson實現(xiàn)分布式鎖,在redis部署使用單點/集群分片/哨兵模式下,有區(qū)別嗎
Redis部署單點/集群分片/哨兵模式下,使用Redisson的方式有區(qū)別嗎?
一、實現(xiàn)思路:
對于 Redis 的不同部署模式(單點、集群分片、哨兵模式),Redisson 都提供了相應的配置方式來支持分布式鎖的實現(xiàn),但在細節(jié)和性能上會有一些區(qū)別。
在單點模式下,配置相對簡單,直接指向單個 Redis 服務器即可。
集群分片模式下,需要配置多個 Redis 節(jié)點信息,Redisson 會自動處理數(shù)據(jù)分片和節(jié)點間的通信,確保分布式鎖的可靠性和性能。
哨兵模式下,需要配置哨兵節(jié)點信息,Redisson 會根據(jù)哨兵節(jié)點來監(jiān)控 Redis 主從的狀態(tài),在主節(jié)點故障時自動切換到新的主節(jié)點,保證分布式鎖的可用性。
二、不同部署模式下的實現(xiàn)細節(jié):
- 單點模式:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonSingleNodeLock {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置
Config config = new Config();
// 設置 Redis 單點地址
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 執(zhí)行加鎖后的業(yè)務邏輯
System.out.println("Lock acquired, doing something...");
} finally {
// 解鎖
lock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
上述代碼中,使用 config.useSingleServer().setAddress("redis://127.0.0.1:6379") 配置了一個 Redis 單點地址,創(chuàng)建了 Redisson 客戶端并獲取鎖。這種模式下,Redisson 直接與該單點 Redis 服務器通信,實現(xiàn)簡單,但存在單點故障風險。
- 集群分片模式:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
public class RedissonClusterLock {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置
Config config = new Config();
ClusterServersConfig clusterConfig = config.useClusterServers();
// 添加多個 Redis 集群節(jié)點
clusterConfig.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001", "redis://127.0.0.1:7002");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 執(zhí)行加鎖后的業(yè)務邏輯
System.out.println("Lock acquired in cluster mode, doing something...");
} finally {
// 解鎖
lock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
在集群分片模式下,通過 config.useClusterServers() 開啟集群配置,使用 clusterConfig.addNodeAddress 添加多個 Redis 集群節(jié)點。Redisson 會根據(jù) Redis 集群的特點自動處理數(shù)據(jù)的分片存儲和節(jié)點間的通信,分布式鎖會分布在不同的節(jié)點上,提高了系統(tǒng)的性能和容錯性。
- 哨兵模式:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
public class RedissonSentinelLock {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置
Config config = new Config();
SentinelServersConfig sentinelConfig = config.useSentinelServers();
// 設置哨兵節(jié)點地址
sentinelConfig.addSentinelAddress("redis://127.0.0.1:26379", "redis://127.0.0.1:26380");
// 設置主節(jié)點名稱
sentinelConfig.setMasterName("mymaster");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 執(zhí)行加鎖后的業(yè)務邏輯
System.out.println("Lock acquired in sentinel mode, doing something...");
} finally {
// 解鎖
lock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
在哨兵模式下,使用 config.useSentinelServers() 開啟哨兵配置,通過 sentinelConfig.addSentinelAddress 添加哨兵節(jié)點地址,sentinelConfig.setMasterName 設置主節(jié)點名稱。Redisson 會根據(jù)哨兵的監(jiān)控信息,在主節(jié)點故障時自動切換到新的主節(jié)點,保證分布式鎖在 Redis 主從切換時的有效性和可靠性。
三、區(qū)別總結:
單點模式:
- 配置簡單,僅需指定一個 Redis 節(jié)點地址。
- 性能和可靠性取決于單個 Redis 服務器,存在單點故障風險,一旦該節(jié)點故障,分布式鎖將無法使用。
- 適合開發(fā)測試環(huán)境或對可靠性要求不高的小型系統(tǒng)。
集群分片模式:
- 配置多個 Redis 節(jié)點,可充分利用集群的性能和存儲能力。
- 分布式鎖會根據(jù) Redis 集群的特性在不同節(jié)點間分布,提高了系統(tǒng)的性能和存儲容量。
- 需要注意集群的拓撲結構和節(jié)點的狀態(tài)維護,確保集群的正常運行。
- 適合高負載、大規(guī)模數(shù)據(jù)存儲和操作的系統(tǒng)。
哨兵模式:
主要利用哨兵節(jié)點監(jiān)控 Redis 主從狀態(tài),在主節(jié)點故障時自動切換,保證分布式鎖的可用性。
配置涉及哨兵節(jié)點地址和主節(jié)點名稱,確保哨兵正常工作。
可以提高系統(tǒng)的容錯性,適合對系統(tǒng)可用性要求較高,希望在主節(jié)點故障時能自動切換到新主節(jié)點的場景。
四、使用注意事項:
無論哪種模式,使用分布式鎖時,都要確保加鎖和解鎖的操作在正確的代碼塊中執(zhí)行,避免死鎖或鎖無法釋放的情況。
在集群分片和哨兵模式下,要確保節(jié)點的網絡和硬件配置合理,避免因網絡延遲或硬件故障導致分布式鎖的性能下降或失效。
對于不同的業(yè)務場景,選擇合適的 Redis 部署模式和相應的 Redisson 配置,以平衡性能、可靠性和開發(fā)成本。
分布式鎖的超時時間設置需要謹慎,避免因超時導致業(yè)務邏輯異常,同時要考慮不同部署模式下可能的網絡延遲和 Redis 操作延遲對鎖超時的影響。
總之,Redisson 在不同的 Redis 部署模式下都能實現(xiàn)分布式鎖,但不同模式在配置、性能、可靠性等方面有各自的特點,需要根據(jù)具體的業(yè)務需求和系統(tǒng)架構來選擇合適的模式。
3、redisson獲取鎖
請問 RLock lock = redisson.getLock("myLock");和 lock.lock(); 有啥區(qū)別
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 在此執(zhí)行需要加鎖的代碼邏輯
System.out.println("執(zhí)行加鎖后的操作");
} finally {
// 解鎖
lock.unlock();
}
一、RLock lock = redisson.getLock("myLock"); 的解釋:
- 這行代碼的主要目的是從 Redisson 客戶端中獲取一個分布式鎖對象,該對象的名稱是
"myLock"。 redisson.getLock("myLock")方法調用后,Redisson 會根據(jù)鎖的名稱在 Redis 中創(chuàng)建或查找對應的鎖信息,但此時并未真正加鎖。- 它返回的是一個
RLock類型的對象,RLock是 Redisson 對分布式鎖的接口,實現(xiàn)了java.util.concurrent.locks.Lock接口,同時提供了一些額外的特性,如可重入性、公平鎖、鎖的超時等,這些特性是對 Redis 分布式鎖功能的增強。
二、lock.lock(); 的解釋:
- 這行代碼是對之前獲取到的
RLock對象lock進行加鎖操作。 - 當調用
lock.lock();時,Redisson 會與 Redis 服務器通信,嘗試獲取鎖。 - 如果鎖是可用的(沒有其他客戶端持有該鎖),當前客戶端將獲得該鎖,后續(xù)代碼將可以繼續(xù)執(zhí)行。
- 如果鎖已被其他客戶端持有,
lock.lock();會阻塞當前線程,直到鎖被釋放或超時(可設置超時時間)。 - 它會在 Redis 中設置相應的鎖鍵值,同時使用一些機制(如基于 Redis 的數(shù)據(jù)結構和算法)來保證分布式環(huán)境下的鎖的互斥性和一致性,確保同一時間只有一個客戶端可以獲得該鎖。
三、區(qū)別總結:
RLock lock = redisson.getLock("myLock");是獲取鎖對象的操作,是為加鎖做準備,它只是一個對象的創(chuàng)建和獲取步驟,不涉及實際的鎖競爭和鎖的持有。lock.lock();是真正的加鎖操作,會觸發(fā)鎖的競爭機制,嘗試在 Redis 上獲取鎖,可能會阻塞線程,直到獲取到鎖或者超時。
四、示例代碼的整體流程解釋:
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖
lock.lock();
// 在此執(zhí)行需要加鎖的代碼邏輯
System.out.println("執(zhí)行加鎖后的操作");
} finally {
// 解鎖
lock.unlock();
}
- 首先通過
redisson.getLock("myLock");獲取名為"myLock"的分布式鎖對象lock。 - 然后使用
lock.lock();對這個鎖進行加鎖操作,如果當前沒有其他客戶端持有該鎖,當前客戶端會成功加鎖,之后執(zhí)行System.out.println("執(zhí)行加鎖后的操作");等業(yè)務邏輯。 - 最后在
finally塊中調用lock.unlock();確保鎖會被釋放,無論業(yè)務邏輯是否正常執(zhí)行,這是一個良好的編程習慣,防止因異常導致鎖無法釋放,影響其他客戶端對鎖的使用。
總之,getLock 是為加鎖做準備,lock 是實際的加鎖操作,兩者結合使用可以實現(xiàn) Redisson 分布式鎖的獲取和使用,保障分布式環(huán)境下的資源競爭和互斥訪問。
4、getLock、getSpinLock、getRedLock、getReadWriteLock區(qū)別
Redisson在分布式獲取鎖的時候,有多個獲取鎖的方式: getLock、getSpinLock、getRedLock、getReadWriteLock。
在獲取分布式鎖業(yè)務的場景下,更適合哪種方式?順便講解下各自的用法
一、不同鎖的特點及用法:
getLock:
特點:這是最常用的獲取鎖的方式,提供了一個可重入鎖,支持公平鎖和非公平鎖??芍厝腈i意味著一個線程可以多次獲取同一個鎖而不會產生死鎖,只要它每次都能正確釋放鎖。它可以設置鎖的超時時間,以防止死鎖情況。
用法:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonGetLockExample {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// 獲取鎖對象
RLock lock = redisson.getLock("myLock");
try {
// 加鎖,可設置超時時間,防止死鎖
lock.lock(10, TimeUnit.SECONDS);
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under getLock");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 解鎖
lock.unlock();
}
redisson.shutdown();
}
}
上述代碼通過 redisson.getLock("myLock") 獲取一個普通的可重入鎖,使用 lock(10, TimeUnit.SECONDS) 加鎖并設置 10 秒超時時間,在 finally 塊中解鎖。它適用于一般的分布式資源競爭場景,如多個線程或服務需要互斥訪問某個共享資源。
getSpinLock:- 特點:這是一種自旋鎖,當線程嘗試獲取鎖失敗時,會不斷循環(huán)嘗試獲取鎖,而不是阻塞線程。自旋鎖在鎖持有時間較短的情況下,可以減少線程上下文切換的開銷,但如果鎖持有時間較長,會消耗大量的 CPU 資源。
- 用法:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonGetSpinLockExample {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// 獲取自旋鎖對象
RLock spinLock = redisson.getSpinLock("mySpinLock");
try {
// 加鎖
spinLock.lock();
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under getSpinLock");
} finally {
// 解鎖
spinLock.unlock();
}
redisson.shutdown();
}
}
在這個示例中,使用 redisson.getSpinLock("mySpinLock") 獲取自旋鎖,調用 lock() 方法嘗試加鎖,線程會在獲取鎖失敗時進行自旋等待。適用于鎖競爭不激烈且鎖持有時間較短的場景,例如在高并發(fā)下對一些快速操作的資源進行加鎖。
getRedLock:- 特點:RedLock 是一種基于多個 Redis 節(jié)點的分布式鎖算法,用于解決單點故障和數(shù)據(jù)不一致的問題。它會在多個 Redis 節(jié)點上同時嘗試獲取鎖,只有在大多數(shù)節(jié)點上成功獲取鎖時才認為加鎖成功,提高了鎖的可靠性。
- 用法:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.api.RedissonRxClient;
import org.redisson.config.Config;
public class RedissonGetRedLockExample {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient1 = Redisson.create(config);
// 假設這里有多個 Redisson 客戶端連接不同的 Redis 節(jié)點
RedissonClient redissonClient2 = Redisson.create(config);
RedissonClient redissonClient3 = Redisson.create(config);
RLock lock1 = redissonClient1.getLock("myRedLock");
RLock lock2 = redissonClient2.getLock("myRedLock");
RLock lock3 = redissonClient3.getLock("myRedLock");
RLock redLock = redisson.getRedLock(lock1, lock2, lock3);
try {
// 加鎖
redLock.lock();
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under getRedLock");
} finally {
// 解鎖
redLock.unlock();
}
redissonClient1.shutdown();
redissonClient2.shutdown();
redissonClient3.shutdown();
}
}
在這個例子中,首先創(chuàng)建多個 Redisson 客戶端連接不同的 Redis 節(jié)點,然后通過 redisson.getRedLock(lock1, lock2, lock3) 生成一個 RedLock,它會在多個節(jié)點上嘗試加鎖。適用于對鎖的可靠性要求極高,不能容忍單點故障的場景,比如在分布式系統(tǒng)中對關鍵資源的保護,需要保證鎖的強一致性和高可用性。
getReadWriteLock:- 特點:提供了讀寫鎖功能,讀寫鎖允許多個讀操作同時進行,但寫操作是獨占的,讀寫互斥。讀鎖可以被多個線程同時持有,但寫鎖只能被一個線程持有,且寫鎖的優(yōu)先級高于讀鎖。
- 用法:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonGetReadWriteLockExample {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// 獲取讀寫鎖對象
RReadWriteLock readWriteLock = redisson.getReadWriteLock("myReadWriteLock");
// 獲取寫鎖
RLock writeLock = readWriteLock.writeLock();
try {
// 加寫鎖
writeLock.lock();
// 執(zhí)行寫操作的業(yè)務邏輯
System.out.println("Write operation under getReadWriteLock");
} finally {
// 解鎖
writeLock.unlock();
}
// 獲取讀鎖
RLock readLock = readWriteLock.readLock();
try {
// 加讀鎖
readLock.lock();
// 執(zhí)行讀操作的業(yè)務邏輯
System.out.println("Read operation under getReadWriteLock");
} finally {
// 解鎖
readLock.unlock();
}
redisson.shutdown();
}
}
在上述代碼中,使用 redisson.getReadWriteLock("myReadWriteLock") 獲取讀寫鎖對象,通過 writeLock() 獲取寫鎖,通過 readLock() 獲取讀鎖。適用于讀多寫少的場景,例如在分布式緩存中,多個線程可以同時讀取數(shù)據(jù),但寫數(shù)據(jù)時需要獨占鎖,以保證數(shù)據(jù)的一致性。
二、適合的場景總結:
getLock:適合大多數(shù)普通的分布式鎖場景,對鎖的可靠性和性能有一定要求,但沒有特殊的分布式鎖需求。getSpinLock:適用于鎖競爭不激烈且鎖持有時間短的情況,通過自旋避免線程切換,提高性能,但長時間等待會消耗大量 CPU。getRedLock:適合對鎖的可靠性和容錯性要求極高的場景,例如金融交易系統(tǒng)、分布式任務調度等,防止單點故障對鎖的影響。getReadWriteLock:適合讀寫分離的場景,如分布式數(shù)據(jù)庫、緩存等系統(tǒng),在讀多寫少的情況下,優(yōu)化鎖的使用,提高并發(fā)性能。
根據(jù)不同的業(yè)務需求和場景,可以選擇不同的 Redisson 鎖獲取方式,確保分布式系統(tǒng)中資源的互斥訪問和一致性。
5、使用Redisson,redis數(shù)據(jù)庫都不設置密碼嗎
一、設置 Redis 密碼的必要性:
在生產環(huán)境中,為了保證 Redis 數(shù)據(jù)庫的安全性,通常是需要設置密碼的。不設置密碼會導致 Redis 數(shù)據(jù)庫面臨安全風險,可能被未授權的用戶訪問和操作,進而影響數(shù)據(jù)的安全性和系統(tǒng)的穩(wěn)定性。
二、使用 Redisson 時設置 Redis 密碼的方法:
以下是在 Redisson 中設置 Redis 密碼的示例代碼:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonGetReadWriteLockExample {
public static void main(String[] args) {
Config config = new Config();
// 設置 Redis 單點服務器信息并添加密碼
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("yourRedisPassword");
RedissonClient redisson = Redisson.create(config);
// 獲取讀寫鎖對象
RReadWriteLock readWriteLock = redisson.getReadWriteLock("myReadWriteLock");
// 獲取寫鎖
RLock writeLock = readWriteLock.writeLock();
try {
// 加寫鎖
writeLock.lock();
// 執(zhí)行寫操作的業(yè)務邏輯
System.out.println("Write operation under getReadWriteLock");
} finally {
// 解鎖
writeLock.unlock();
}
// 獲取讀鎖
RLock readLock = readWriteLock.readLock();
try {
// 加讀鎖
readLock.lock();
// 執(zhí)行讀操作的業(yè)務邏輯
System.out.println("Read operation under getReadWriteLock");
} finally {
// 解鎖
readLock.unlock();
}
redisson.shutdown();
}
}
上述代碼在 config.useSingleServer() 之后,通過 .setPassword("yourRedisPassword") 方法設置了 Redis 的密碼,你需要將 "yourRedisPassword" 替換為實際的 Redis 密碼。
三、代碼解釋:
- 首先,我們創(chuàng)建了一個 Redisson 的配置對象
Config。 - 然后使用
config.useSingleServer()來指定 Redis 是單點服務器模式,并使用setAddress()方法設置 Redis 服務器的地址。 - 通過
setPassword()方法將 Redis 的密碼設置進去,確保只有提供正確密碼的客戶端才能連接和操作 Redis。 - 接著使用
Redisson.create(config)創(chuàng)建 Redisson 客戶端。 - 后續(xù)的代碼與之前一樣,獲取讀寫鎖、加鎖、執(zhí)行業(yè)務邏輯、解鎖操作。
四、不同部署模式下設置密碼的注意事項:
單點模式:
- 如上述示例,直接使用
setPassword()即可。
- 如上述示例,直接使用
集群模式:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
public class RedissonClusterWithPassword {
public static void main(String[] args) {
Config config = new Config();
ClusterServersConfig clusterConfig = config.useClusterServers();
// 設置集群節(jié)點地址
clusterConfig.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001", "redis://127.0.0.1:7002");
// 設置密碼
clusterConfig.setPassword("yourRedisPassword");
RedissonClient redisson = Redisson.create(config);
// 后續(xù)操作,如獲取鎖等,與單點模式類似
//...
redisson.shutdown();
}
}
這里使用 clusterConfig.setPassword() 來設置集群模式下的 Redis 密碼。
- 哨兵模式:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
public class RedissonSentinelWithPassword {
public static void main(String[] args) {
Config config = new Config();
SentinelServersConfig sentinelConfig = config.useSentinelServers();
// 設置哨兵節(jié)點地址
sentinelConfig.addSentinelAddress("redis://127.0.0.1:26379", "redis://127.0.0.1:26380");
// 設置主節(jié)點名稱
sentinelConfig.setMasterName("mymaster");
// 設置密碼
sentinelConfig.setPassword("yourRedisPassword");
RedissonClient redisson = Redisson.create(config);
// 后續(xù)操作,如獲取鎖等,與單點模式類似
//...
redisson.shutdown();
}
}
在哨兵模式下,使用 sentinelConfig.setPassword() 來設置密碼。
五、總結:
在使用 Redisson 時,無論 Redis 采用何種部署模式,都應該設置密碼以保障 Redis 數(shù)據(jù)庫的安全性。通過上述方法,可以方便地在不同的 Redis 部署模式下為 Redisson 配置相應的密碼,從而使 Redisson 客戶端在連接 Redis 時提供正確的密碼信息,確保連接的安全性。
6、Redisson使用公平鎖 怎樣獲取鎖
一、使用 Redisson 獲取公平鎖的實現(xiàn)思路:
- 首先創(chuàng)建 Redisson 的配置對象
Config。 - 使用
config.useSingleServer()或相應的集群、哨兵模式配置方法設置 Redis 服務器信息。 - 創(chuàng)建 Redisson 客戶端。
- 通過
redisson.getFairLock("yourLockName")獲取公平鎖對象。 - 調用
lock()方法加鎖,執(zhí)行需要加鎖的業(yè)務邏輯。 - 在
finally塊中使用unlock()方法解鎖,確保鎖被正確釋放。
二、具體代碼示例:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonFairLockExample {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置對象
Config config = new Config();
// 假設使用單點 Redis 服務器,設置服務器地址
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取公平鎖對象,指定鎖名稱
RLock fairLock = redisson.getFairLock("myFairLock");
try {
// 加鎖
fairLock.lock();
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under fair lock");
} finally {
// 解鎖
fairLock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
三、代碼解釋:
Config config = new Config();:創(chuàng)建一個 Redisson 的配置對象,用于后續(xù)的配置。config.useSingleServer().setAddress("redis://127.0.0.1:6379");:設置 Redis 服務器為單點模式,并指定服務器的地址,你可以根據(jù)實際情況修改該地址。RedissonClient redisson = Redisson.create(config);:使用配置對象創(chuàng)建 Redisson 客戶端。RLock fairLock = redisson.getFairLock("myFairLock");:通過redisson.getFairLock("myFairLock")方法獲取一個名為myFairLock的公平鎖對象。公平鎖的特點是按照請求鎖的順序來分配鎖,避免了某些線程長時間等待鎖的情況,保證了鎖分配的公平性。fairLock.lock();:調用lock()方法加鎖,若當前鎖已被其他線程持有,該線程會等待,直到獲取到鎖。- 在
finally塊中調用fairLock.unlock();解鎖,確保鎖能正常釋放,避免死鎖和資源泄漏。 redisson.shutdown();:關閉 Redisson 客戶端,釋放相關資源。
四、使用說明:
- 你可以根據(jù)需要修改
setAddress中的 Redis 服務器地址,使其符合你的 Redis 部署。 - 對于鎖的名稱
myFairLock,可以根據(jù)不同的業(yè)務場景進行修改,確保不同的業(yè)務使用不同的鎖名稱,避免鎖沖突。 - 在
try塊中添加你需要加鎖的業(yè)務邏輯,如數(shù)據(jù)庫操作、資源訪問等,確保這些操作在加鎖期間是線程安全的。
使用公平鎖可以使線程按照請求的順序獲取鎖,在一些對鎖獲取順序有要求的場景中非常有用,例如在任務調度、資源排隊分配等場景中,能保證各個任務或資源的公平性和有序性。同時,使用 try-finally 結構確保鎖的正確釋放,是保證程序健壯性的重要手段。
7、Redisson在使用 公平鎖與非公平鎖的區(qū)別
一、公平鎖與非公平鎖的基本概念:
公平鎖:
- 公平鎖是指多個線程在獲取鎖時,會按照請求鎖的順序依次獲得鎖。它會維護一個等待隊列,當鎖被釋放時,會將鎖分配給等待時間最長的線程,確保了鎖分配的公平性。在高并發(fā)情況下,線程等待鎖的時間相對更加平均,避免了某些線程長時間無法獲取鎖的情況。
非公平鎖:
- 非公平鎖不考慮線程請求鎖的順序,線程在獲取鎖時會直接嘗試獲取,獲取不到才會進入等待隊列。這可能導致某些線程頻繁獲取鎖,而其他線程長時間等待,甚至出現(xiàn) “饑餓” 現(xiàn)象,但在性能上可能會比公平鎖稍好一些,因為減少了維護等待隊列的開銷。
二、使用 Redisson 實現(xiàn)公平鎖和非公平鎖的區(qū)別:
- 公平鎖的使用示例:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonFairLockExample {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置對象
Config config = new Config();
// 假設使用單點 Redis 服務器,設置服務器地址
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取公平鎖對象,指定鎖名稱
RLock fairLock = redisson.getFairLock("myFairLock");
try {
// 加公平鎖
fairLock.lock();
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under fair lock");
} finally {
// 解鎖
fairLock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
在上述代碼中,通過 redisson.getFairLock("myFairLock") 獲取公平鎖對象,然后使用 lock() 方法加鎖,執(zhí)行完業(yè)務邏輯后通過 unlock() 方法解鎖。公平鎖保證了線程按照請求順序獲取鎖,當多個線程同時競爭時,會依次獲取鎖,不會出現(xiàn)插隊現(xiàn)象。
- 非公平鎖的使用示例:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonNonFairLockExample {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 配置對象
Config config = new Config();
// 假設使用單點 Redis 服務器,設置服務器地址
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 創(chuàng)建 Redisson 客戶端
RedissonClient redisson = Redisson.create(config);
// 獲取普通鎖對象,默認為非公平鎖,指定鎖名稱
RLock nonFairLock = redisson.getLock("myNonFairLock");
try {
// 加非公平鎖
nonFairLock.lock();
// 執(zhí)行需要加鎖的業(yè)務邏輯
System.out.println("Business logic under non-fair lock");
} finally {
// 解鎖
nonFairLock.unlock();
}
// 關閉 Redisson 客戶端
redisson.shutdown();
}
}
這里通過 redisson.getLock("myNonFairLock") 獲取普通鎖對象,它默認是非公平鎖,加鎖和解鎖的操作與公平鎖類似,但在多線程競爭鎖時,可能出現(xiàn)線程不按順序獲取鎖的情況。
三、性能和使用場景的區(qū)別:
性能方面:
- 公平鎖:由于需要維護等待隊列,在鎖的分配和管理上會有額外的開銷,性能可能稍遜一籌,尤其是在高并發(fā)且鎖競爭激烈的情況下,可能會因為頻繁的隊列操作而降低性能。
- 非公平鎖:無需維護等待隊列,減少了額外的操作,性能相對較好,對于性能要求較高且鎖持有時間較短、鎖競爭不那么激烈的場景下,可能會表現(xiàn)得更好。
使用場景方面:
公平鎖:適用于對鎖獲取順序有要求的場景,例如在任務調度、資源分配等業(yè)務場景中,需要保證每個任務或線程按照請求的先后順序獲取鎖,避免某些任務長時間等待,保證系統(tǒng)的公平性和有序性。
非公平鎖:適用于對性能要求較高,對鎖獲取順序沒有嚴格要求的場景,例如在一些短時間的操作、并發(fā)度較高但對公平性要求不高的場景下,可以減少鎖獲取的等待時間,提高系統(tǒng)的整體性能。
總之,選擇公平鎖還是非公平鎖需要根據(jù)具體的業(yè)務需求和性能要求來決定。如果需要保證線程獲取鎖的公平性,避免某些線程長時間等待,可以使用公平鎖;如果對性能有更高的要求,對鎖獲取順序沒有嚴格要求,可以使用非公平鎖。
8、RLock.unlock使用
當獲取到的鎖,已經過期了,再執(zhí)行releaseLock時,可以先檢查下再執(zhí)行releaseLock嗎?防止release的時候報錯
public void releaseLock(RLock lock){
lock.unlock();
}
一、解決思路:
在執(zhí)行
releaseLock方法時,需要先檢查當前線程是否持有鎖,以避免在鎖已過期或已被其他線程持有(如因超時釋放)的情況下執(zhí)行解鎖操作而導致錯誤。可以使用
RLock提供的isHeldByCurrentThread方法來檢查當前線程是否持有鎖。
二、修改后的代碼:
import org.redisson.api.RLock;
public class RedissonLockUtils {
public void releaseLock(RLock lock) {
// 檢查當前線程是否持有鎖
if (lock!= null && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
三、代碼解釋:
public void releaseLock(RLock lock):定義了一個釋放鎖的方法,接收一個RLock類型的鎖對象作為參數(shù)。if (lock!= null && lock.isHeldByCurrentThread()):首先檢查lock對象是否不為空,并且使用isHeldByCurrentThread方法檢查當前線程是否持有該鎖。lock!= null:避免null引用導致的NullPointerException。isHeldByCurrentThread():該方法會檢查當前線程是否持有鎖。如果當前線程持有鎖,該方法返回true,否則返回false。
lock.unlock();:當滿足上述條件時,執(zhí)行解鎖操作,確保解鎖操作的安全性。
四、使用說明:
- 當調用
releaseLock方法時,將獲取到的RLock對象作為參數(shù)傳遞給該方法。例如:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class Main {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
RLock lock = redisson.getLock("myLock");
RedissonLockUtils lockUtils = new RedissonLockUtils();
try {
lock.lock();
// 業(yè)務邏輯
} finally {
lockUtils.releaseLock(lock);
}
redisson.shutdown();
}
}
在上述代碼中,先創(chuàng)建了一個 RedissonLockUtils 類的實例 lockUtils,在 finally 塊中調用 lockUtils.releaseLock(lock) 方法釋放鎖。在 releaseLock 方法中,會先檢查當前線程是否持有鎖,只有當當前線程持有鎖時才會執(zhí)行解鎖操作,避免了因鎖過期或被其他線程釋放后再解鎖而引發(fā)的異常。
通過這種方式,可以確保解鎖操作的正確性和安全性,避免在鎖已失效的情況下進行不必要的解鎖操作,從而防止報錯,提高程序的健壯性。
到此這篇關于RedisTemplate和Redisson的區(qū)別的文章就介紹到這了,更多相關RedisTemplate Redisson區(qū)別內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 使用redisTemplate從redis獲取所有數(shù)據(jù)
- 解決RedisTemplate調用increment報錯問題
- 解決使用redisTemplate高并發(fā)下連接池滿的問題
- 如何解決redisTemplate注入為空問題
- SpringBoot通過RedisTemplate執(zhí)行Lua腳本的方法步驟
- RedisTemplate常用操作方法總結(set、hash、list、string等)
- java 用redisTemplate 的 Operations存取list集合操作
- Redis之RedisTemplate配置方式(序列和反序列化)
- 在RedisTemplate中使用scan代替keys指令操作
- 關于RedisTemplate之opsForValue的使用說明
相關文章
Mybatis Plus 增刪改查的實現(xiàn)(小白教程)
本文主要介紹了Mybatis Plus 增刪改查,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
SpringBoot打印POST請求原始入?yún)ody體方式
這篇文章主要介紹了SpringBoot打印POST請求原始入?yún)ody體方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
IDEA 集成log4j將SQL語句打印在控制臺上的實現(xiàn)操作
這篇文章主要介紹了IDEA 集成log4j將SQL語句打印在控制臺上的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
IDEA創(chuàng)建Maven一直爆紅無法下載的問題解決辦法
這篇文章主要介紹了關于IDEA創(chuàng)建Maven一直爆紅無法下載的問題的解決辦法,文中圖文結合的方式給大家講解的非常詳細,對大家解決辦法非常有用,需要的朋友可以參考下2024-06-06
spring mvc利用ajax向controller傳遞對象的方法示例
這篇文章主要給大家介紹了關于spring mvc利用ajax向controller傳遞對象的相關資料,文中通過示例代碼將步驟介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來跟著小編一起學習學習吧。2017-07-07

