<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Lettuce 是 Redis 的一款高階 Java 使用者端,與 Jedis 並列成為最熱門的使用者端之一,目前已成為 SpringBoot 2.0 版本預設的 redis 使用者端。
相比老牌 Jedis,Lettuce 屬於後起之秀,不僅功能豐富,而且提供了很多新的功能特性,比如非同步操作、響應式程式設計等等,同時還解決了 Jedis 中執行緒不安全的問題。
廢話不多說了,如何使用呢?請看下文!
首先,建立一個 maven 專案,引入lettuce-core
包,就可以使用了。
<dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>5.3.1.RELEASE</version> </dependency>
使用 lettuce 連線 redis,測試是否能正常聯通!
public class LettuceMain { public static void main(String[] args) { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1") .withPort(6379) .withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient redisClient = RedisClient.create(redisUri); StatefulRedisConnection<String, String> connection = redisClient.connect(); RedisCommands<String, String> commands = connection.sync(); System.out.println(commands.ping()); connection.close(); redisClient.shutdown(); } }
基本上只要是 Jedis 支援的同步命令操作,Lettuce 都支援。
下面,我們以同步操作字串為例,Lettuce 的 api 操作如下!
public class LettuceSyncMain { public static void main(String[] args) { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient redisClient = RedisClient.create(redisUri); StatefulRedisConnection<String, String> connection = redisClient.connect(); //獲取同步操作命令工具 RedisCommands<String, String> commands = connection.sync(); System.out.println("清空資料:"+commands.flushdb()); System.out.println("判斷某個鍵是否存在:"+commands.exists("username")); System.out.println("新增<'username','xmr'>的鍵值對:"+commands.set("username", "xmr")); System.out.println("新增<'password','password'>的鍵值對:"+commands.set("password", "123")); System.out.println("獲取<'password'>鍵的值:"+commands.get("password")); System.out.println("系統中所有的鍵如下:" + commands.keys("*")); System.out.println("刪除鍵password:"+commands.del("password")); System.out.println("判斷鍵password是否存在:"+commands.exists("password")); System.out.println("設定鍵username的過期時間為5s:"+commands.expire("username", 5L)); System.out.println("檢視鍵username的剩餘生存時間:"+commands.ttl("username")); System.out.println("移除鍵username的生存時間:"+commands.persist("username")); System.out.println("檢視鍵username的剩餘生存時間:"+commands.ttl("username")); System.out.println("檢視鍵username所儲存的值的型別:"+commands.type("username")); connection.close(); redisClient.shutdown(); } }
除此之外,Lettuce 還支援非同步操作,將上面的操作改成非同步處理,結果如下!
public class LettuceASyncMain { public static void main(String[] args) throws Exception { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient redisClient = RedisClient.create(redisUri); StatefulRedisConnection<String, String> connection = redisClient.connect(); //獲取非同步操作命令工具 RedisAsyncCommands<String, String> commands = connection.async(); System.out.println("清空資料:"+commands.flushdb().get()); System.out.println("判斷某個鍵是否存在:"+commands.exists("username").get()); System.out.println("新增<'username','xmr'>的鍵值對:"+commands.set("username", "xmr").get()); System.out.println("新增<'password','password'>的鍵值對:"+commands.set("password", "123").get()); System.out.println("獲取<'password'>鍵的值:"+commands.get("password").get()); System.out.println("系統中所有的鍵如下:" + commands.keys("*").get()); System.out.println("刪除鍵password:"+commands.del("password").get()); System.out.println("判斷鍵password是否存在:"+commands.exists("password").get()); System.out.println("設定鍵username的過期時間為5s:"+commands.expire("username", 5L).get()); System.out.println("檢視鍵username的剩餘生存時間:"+commands.ttl("username").get()); System.out.println("移除鍵username的生存時間:"+commands.persist("username").get()); System.out.println("檢視鍵username的剩餘生存時間:"+commands.ttl("username").get()); System.out.println("檢視鍵username所儲存的值的型別:"+commands.type("username").get()); connection.close(); redisClient.shutdown(); } }
Lettuce 除了支援非同步程式設計以外,還支援響應式程式設計,Lettuce 引入的響應式程式設計框架是Project Reactor
,如果沒有響應式程式設計經驗可以先自行了解一下,存取地址https://projectreactor.io/。
響應式程式設計使用案例如下:
public class LettuceMain { public static void main(String[] args) throws Exception { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient redisClient = RedisClient.create(redisUri); StatefulRedisConnection<String, String> connection = redisClient.connect(); //獲取響應式API操作命令工具 RedisReactiveCommands<String, String> commands = connection.reactive(); Mono<String> setc = commands.set("name", "mayun"); System.out.println(setc.block()); Mono<String> getc = commands.get("name"); getc.subscribe(System.out::println); Flux<String> keys = commands.keys("*"); keys.subscribe(System.out::println); //開啟一個事務,先把count設定為1,再將count自增1 commands.multi().doOnSuccess(r -> { commands.set("count", "1").doOnNext(value -> System.out.println("count1:" + value)).subscribe(); commands.incr("count").doOnNext(value -> System.out.println("count2:" + value)).subscribe(); }).flatMap(s -> commands.exec()) .doOnNext(transactionResult -> System.out.println("transactionResult:" + transactionResult.wasDiscarded())).subscribe(); Thread.sleep(1000 * 5); connection.close(); redisClient.shutdown(); } }
Lettuce 還支援 redis 的訊息釋出和訂閱,具體實現案例如下:
public class LettuceReactiveMain1 { public static void main(String[] args) throws Exception { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient redisClient = RedisClient.create(redisUri); //獲取釋出訂閱操作命令工具 StatefulRedisPubSubConnection<String, String> pubsubConn = redisClient.connectPubSub(); pubsubConn.addListener(new RedisPubSubListener<String, String>() { @Override public void unsubscribed(String channel, long count) { System.out.println("[unsubscribed]" + channel); } @Override public void subscribed(String channel, long count) { System.out.println("[subscribed]" + channel); } @Override public void punsubscribed(String pattern, long count) { System.out.println("[punsubscribed]" + pattern); } @Override public void psubscribed(String pattern, long count) { System.out.println("[psubscribed]" + pattern); } @Override public void message(String pattern, String channel, String message) { System.out.println("[message]" + pattern + " -> " + channel + " -> " + message); } @Override public void message(String channel, String message) { System.out.println("[message]" + channel + " -> " + message); } }); RedisPubSubAsyncCommands<String, String> pubsubCmd = pubsubConn.async(); pubsubCmd.psubscribe("CH"); pubsubCmd.psubscribe("CH2"); pubsubCmd.unsubscribe("CH"); Thread.sleep(100 * 5); pubsubConn.close(); redisClient.shutdown(); } }
Lettuce 使用者端的通訊框架整合了 Netty 的非阻塞 IO 操作,使用者端資源的設定與 Lettuce 的效能、並行和事件處理緊密相關,如果不是特別熟悉使用者端引數設定,不建議在沒有經驗的前提下憑直覺修改預設值,保持預設設定就行。
非叢集環境下,具體的設定案例如下:
public class LettuceMain { public static void main(String[] args) throws Exception { ClientResources resources = DefaultClientResources.builder() .ioThreadPoolSize(4) //I/O執行緒數 .computationThreadPoolSize(4) //任務執行緒數 .build(); RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); ClientOptions options = ClientOptions.builder() .autoReconnect(true)//是否自動重連 .pingBeforeActivateConnection(true)//連線啟用之前是否執行PING命令 .build(); RedisClient client = RedisClient.create(resources, redisUri); client.setOptions(options); StatefulRedisConnection<String, String> connection = client.connect(); RedisCommands<String, String> commands = connection.sync(); commands.set("name", "關羽"); System.out.println(commands.get("name")); connection.close(); client.shutdown(); resources.shutdown(); } }
叢集環境下,具體的設定案例如下:
public class LettuceMain { public static void main(String[] args) throws Exception { ClientResources resources = DefaultClientResources.builder() .ioThreadPoolSize(4) //I/O執行緒數 .computationThreadPoolSize(4) //任務執行緒數 .build(); RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1").withPort(6379).withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); ClusterClientOptions options = ClusterClientOptions.builder() .autoReconnect(true)//是否自動重連 .pingBeforeActivateConnection(true)//連線啟用之前是否執行PING命令 .validateClusterNodeMembership(true)//是否校驗叢集節點的成員關係 .build(); RedisClusterClient client = RedisClusterClient.create(resources, redisUri); client.setOptions(options); StatefulRedisClusterConnection<String, String> connection = client.connect(); RedisAdvancedClusterCommands<String, String> commands = connection.sync(); commands.set("name", "張飛"); System.out.println(commands.get("name")); connection.close(); client.shutdown(); resources.shutdown(); } }
Lettuce 連線設計的時候,就是執行緒安全的,所以一個連線可以被多個執行緒共用,同時 lettuce 連線預設是自動重連的,使用單連線基本可以滿足業務需求,大多數情況下不需要設定連線池,多連線並不會給操作帶來效能上的提升。
但在某些特殊場景下,比如事物操作,使用連線池會是一個比較好的方案,那麼如何設定執行緒池呢?
public class LettuceMain { public static void main(String[] args) throws Exception { RedisURI redisUri = RedisURI.builder() .withHost("127.0.0.1") .withPort(6379) .withPassword("111111") .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient client = RedisClient.create(redisUri); //連線池設定 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxIdle(2); GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport.createGenericObjectPool(client::connect, poolConfig); StatefulRedisConnection<String, String> connection = pool.borrowObject(); RedisCommands<String, String> commands = connection.sync(); commands.set("name", "張飛"); System.out.println(commands.get("name")); connection.close(); pool.close(); client.shutdown(); } }
redis 一般採用主從複製模式,搭建高可用的架構,簡單的說就一個主節點,多個從節點,自動從主節點同步最新資料。
Lettuce 支援自動發現主從模式下的節點資訊,然後儲存到本地,具體設定如下:
public class LettuceMain { public static void main(String[] args) throws Exception { //這裡只需要設定一個節點的連線資訊,不一定需要是主節點的資訊,從節點也可以;可以自動發現主從節點 RedisURI uri = RedisURI.builder().withHost("192.168.31.111").withPort(6379).withPassword("123456").build(); RedisClient client = RedisClient.create(uri); StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uri); //從節點讀取資料 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands<String, String> commands = connection.sync(); commands.set("name", "張飛"); System.out.println(commands.get("name")); connection.close(); client.shutdown(); } }
當然我們也可以手動指定叢集節點來載入,具體設定如下:
public class LettuceMain { public static void main(String[] args) throws Exception { //叢集節點 List<RedisURI> uris = new ArrayList(); uris.add(RedisURI.builder().withHost("192.168.31.111").withPort(6379).withPassword("111111").build()); uris.add(RedisURI.builder().withHost("192.168.31.112").withPort(6379).withPassword("111111").build()); uris.add(RedisURI.builder().withHost("192.168.31.113").withPort(6379).withPassword("111111").build()); RedisClient client = RedisClient.create(); StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uris); //從節點讀取資料 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands<String, String> commands = connection.sync(); commands.set("name", "張飛"); System.out.println(commands.get("name")); connection.close(); client.shutdown(); } }
哨兵模式,也是 redis 實現服務高可用的一大亮點,具體設定實現如下:
public class LettuceMain { public static void main(String[] args) throws Exception { //叢集節點 List<RedisURI> uris = new ArrayList(); uris.add(RedisURI.builder().withSentinel("192.168.31.111", 26379).withSentinelMasterId("mymaster").withPassword("123456").build()); uris.add(RedisURI.builder().withSentinel("192.168.31.112", 26379).withSentinelMasterId("mymaster").withPassword("123456").build()); uris.add(RedisURI.builder().withSentinel("192.168.31.113", 26379).withSentinelMasterId("mymaster").withPassword("123456").build()); RedisClient client = RedisClient.create(); StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uris); //從節點讀取資料 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands<String, String> commands = connection.sync(); commands.set("name", "趙雲"); System.out.println(commands.get("name")); connection.close(); client.shutdown(); } }
Cluster 叢集模式,是之後推出的一種高可用的架構模型,主要是採用分片方式來儲存資料,具體設定如下:
public class LettuceReactiveMain4 { public static void main(String[] args) throws Exception { Set<RedisURI> uris = new HashSet<>(); uris.add(RedisURI.builder().withHost("192.168.31.111").withPort(7000).withPassword("123456").build()); uris.add(RedisURI.builder().withHost("192.168.31.112").withPort(7000).withPassword("123456").build()); uris.add(RedisURI.builder().withHost("192.168.31.113").withPort(7000).withPassword("123456").build()); uris.add(RedisURI.builder().withHost("192.168.31.114").withPort(7000).withPassword("123456").build()); uris.add(RedisURI.builder().withHost("192.168.31.115").withPort(7000).withPassword("123456").build()); uris.add(RedisURI.builder().withHost("192.168.31.116").withPort(7001).withPassword("123456").build()); RedisClusterClient client = RedisClusterClient.create(uris); StatefulRedisClusterConnection<String, String> connection = client.connect(); RedisAdvancedClusterCommands<String, String> commands = connection.sync(); commands.set("name", "關羽"); System.out.println(commands.get("name")); //選擇從節點,唯讀 NodeSelection<String, String> replicas = commands.replicas(); NodeSelectionCommands<String, String> nodeSelectionCommands = replicas.commands(); Executions<List<String>> keys = nodeSelectionCommands.keys("*"); keys.forEach(key -> System.out.println(key)); connection.close(); client.shutdown(); } }
Lettuce 相比老牌的 Jedis 使用者端,功能更加強大,不僅解決了執行緒安全的問題,還支援非同步和響應式程式設計,支援叢集,Sentinel,管道和編碼器等等功能。
以上介紹的可能只是冰山一角,如果想要了解更多的資訊,可以存取它的官網地址:https://lettuce.io/
到此這篇關於Redis實戰之Lettuce的使用技巧詳解的文章就介紹到這了,更多相關Redis Lettuce內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45