河南省建设厅网网站首页,临沧网站建设公司,广州网站建设公司怎么挑选,一个产品的网络营销方案声明#xff1a;本博客部分内容是从终极SpringBoot讲义摘抄的#xff0c;文字是OCR识别出来的#xff0c;有可能存在识别错误的可能#xff0c;如有错误#xff0c;请大胆指正#xff0c;我马上修改#xff01; 目录 0.官方参考手册API1.连接命令2.key相关命令3.String命…声明本博客部分内容是从终极SpringBoot讲义摘抄的文字是OCR识别出来的有可能存在识别错误的可能如有错误请大胆指正我马上修改 目录 0.官方参考手册API1.连接命令2.key相关命令3.String命令4.List命令5.Set命令6.ZSet命令7.Hash相关命令8.事务相关命令9.Java代码运行示例9.1Redis同步请求代码9.2Redis异步请求代码9.3Redis反应式请求代码 10.订阅发布的Redis的Java代码演示1.Subscriber.java2.subscriber2.java3.Publisher.java 11.杂碎的Redis笔记 在介绍 Redis 的使用之前先简单介绍一下Redis 的数据存储知识。Redis 使用key-value 结构来保存数据其中 value 支持如下 5 种数据类型。
Sting最基本的数据类型可保存任何数据。Hash是key-value 集合类似于 Java 的 Mapkey 和value 都是String 类型的数据。这 种类型主要用于保存对象。List 元素是String 类型的有序集合集合中的元素可以重复。Set 元素是 String 类型的无序集合集合中的元素不能重复。ZSet元素是 string 类型的有序集合集合中的元素不能重复。
Redis 为不同数据类型提供了不同的操作命令因此对于特定类型的数据需要使用对应类型的命令执行操作。 下面简单介绍一些 Redis 的常用命令。
0.官方参考手册API
Spring Data Redis 官方API参考手册 Lettuce 6.2.5.RELEASE API官方API参考手册
1.连接命令
auth 【用户名】 【密码】
这里用户名可以省略假如我的密码是123456可以直接
auth 1234562.key相关命令
与key 相关的常用命令如下。
DEL key:刪除key 対的 key-value 対。DUMP key导出key 对应的值。EXISTS key 判断key 是否存在。EXPIRE key seconds设置key对应的key-value 对经过 seconds 秒后过期。EXPIREAT key timestamp设置key 对应的key-value 对到timestamp 时过期。PEXPIRE key milliseconds: 设置 key 対的 key-value 对经过 milliseconds 毫秒后辻期。PEXPIREAT key milliseconds-timestamp: 设置 key 对应的 key-value 对到 milliseconds-timestamp 时过期。KEYS pattern: 返回匹配 pattern 的所有 key.MOVE key db将指定 key 移动到db 数据库中。PERSIST key删除key 的过期时间key 将持久保持。PTTL key 以毫秒为单位返回指定 key剩余的过期时间。TTL key以秒为单位返回指定key剩余的过期时问。RANDOMKEY从当前数据库返回一个随机的 key。RENAME key newkey: 将 key 重命名 newkey。RENAMENX key newkey: 相当手安全版的 RENAME 当 newkey 不存在オ能重命名TYPE key返回指定 key 存储的数据类型。 运行示例
3.String命令
正如前面所言Redis 内不同数据类型提供了不同的操作命令当 value 是 String 类型時需要使用与 string 相关的命令进行操作。与 string 相关的常用命令如下。
SET key value: 设置 key-value 対。GET key返回指定key 对应的 value。GETRANGE key start end: 获取指定 key 対的 value 中心 start 到 end 的子串。GETSET key value: 指定 key 设置新的 value非返回原来的 value。MGET key [key .]返回一个或多个指定key 对应的 value。SETEX key seconds value设置key-value 对并设置过期时间为 seconds 秒。SETNX key value SET 的安全版本只有当key 不存在时才能设置该key-value 对。SETRANGE key offset value 设置和覆盖指定key对应的 value从原有 value 的 offset 个字符开始如果key 不存在则将前 offset 个字符设为空 (\N0000)。STRLEN key获取 key对应的value 的字符串长度。MSET key value rkey value…]设置多个key value对。MSETNX key value Tkey value…] MSET 的安全版本仅当所有key 都不存在时才能设置 成功。PSETEX key milliseconds value: SETEX 的毫秒版本过期时间以毫秒计算。INCR key将指定 key 中存储的整数值加 1。INCRBY key increment. 将指定key 中存修的整数値増加、inorement 整数值。INCRBYFLOAT key increment. INCRBY 的平点数版木incremcnt 可以是小数。DECR Key将指定 koy 中存储的整数值减1。DECRBY key decrement。将指定key 中存储的整数值少decrement整数值。APPEND key value 在指定key对应的字符串后追加新的value内容 4.List命令
List代表有序的集合可通过命令为List添加或删除元素List最多可包含232-1个元素。实际上Redis的List也具有队列的性质因此它包含了LPUSH LPOP RPUSH RPOP等命令其中LPUSH LPOP表示从List的左边队列头部压入弹出元素RPUSH RPOP表示从List的右边队列尾部压入弹出元素。 与List相关的常用命令如下。 ➢ LINDEX key index获取key对应的List的index处的元素。 ➢ LINSERT key BEFORE|AFTER pivot value在key对应的List的pivot元素之前或之后插入新的value元素。 ➢ LLEN key返回key对应的List的长度。 ➢ LPOP key弹出并返回key对应的List的第一个元素。 ➢ LPUSH key value [value…]向key对应的List的左边队列头部添加一个或多个元素。 ➢ LPUSHX key valueLPUSH的安全版本仅当key对应的List存在时有效。 ➢ LRANGE key start stop获取key对应的List中从start到stop范围内的元素。 ➢ LREM key count value从key对应的value中删除count个value元素。如果count大于0则从左向右删除count个元素如果count小于0则从右向左删除count个元素如果count等于0则删除所有元素。 ➢ LSET key index value将key对应的List的index处的元素改为value。 ➢ LTRIM key start stop修剪List只保留key对应的List中从start到stop之间的元素。 ➢ RPOP key弹出并返回key对应的List的最后一个元素。 ➢ RPOPLPUSH source destination弹出source的最后一个元素添加到destination的左边队列头部并返回该元素。 ➢ RPUSH key value [value…]向key对应的List的右边队列尾部添加一个或多个元素。 ➢ RPUSHX key valueRPUSH的安全版本仅当key对应的List存在时有效。 ➢ BLPOP key [key…] timeoutLPOP的阻塞版本。弹出并返回多个List的第一个元素如果某个List没有元素该命令会阻塞进 程直到所有List都有元素弹出或超时。该命令的B代表Block。 ➢ BRPOP key [key] timeoutRPOP的阻塞版本。弹出并返回多个List的最后一个元素如果某个List没有元素该命令会阻塞进 程直到所有List都有元素弹出或超时。 ➢ BRPOPLPUSH source destination timeoutRPOPLPUSH的阻塞版本如果source中没有元素该命令会阻塞进程直到source有元 素弹出或超时。
5.Set命令
Set代表无序元素不能重复的集合因此Set中的元素都是唯一的。Set最多可包含232-1个元素。Set底层其实是通过Hash表实现的 因此它的删除查找的复杂度都是O1性能很好。 与Set相关的常用命令如下。 ➢ SADD key member [member…]向key对应的Set中添加一个 或多个元素。 ➢ SCARD key返回key对应的Set中元素的个数。 ➢ SDIFF key [key…]计算多个Set之间的差值。 ➢ SDIFFSTORE destination key [key…]SDIFF的存储版本将多个Set之间的差值保存到destination中。 ➢ SINTER key [key…]返回给定Set的交集。 ➢ SINTERSTORE destination key [key…]SINTER的存储版本将给定Set的交集保存到destination中。 ➢ SISMEMBER key member判断member是否为key对应的Set的元素。 ➢ SMEMBERS key返回key对应的Set的全部元素。 ➢ SMOVE source destination member将source中的member元素移到destination中。 ➢ SPOP key弹出key对应的Set中随机的一个元素。 ➢ SRANDMEMBER key [count]返回key对应的Set中随机的count个元素不删除元素。 ➢ SREM key member [member…]删除key对应的Set中的一个或多个元素。 ➢ SUNION key [key…]计算给定Set的并集。 ➢ SUNIONSTORE destination key [key…]SUNION的存储版本将给定Set的并集保存到destination中。
6.ZSet命令
ZSet相当于Set 的增强版它会为每个元素都分配一个double类型的score分数并按该score对集合中元素进行排序。 ZSet集合中的元素不允许重复但元素的score是可以重复的。 与ZSet相关的常用命令如下。 ➢ ZADD key score member [score member…]向ZSet中添加一个或多个元素或者更新已有元素的score。 ➢ ZCARD key返回key对应的ZSet中元素的个数。 ➢ ZCOUNT key min max返回ZSet中score位于min和max之间的元素个数。 ➢ ZDIFF numkeys key [key…] [WITHSCORES]计算给定ZSet之间的差值。该命令在Redis 6.2及更新版本中才可用。 ➢ ZDIFFSTORE destination numkeys key [key…]ZDIFF的存储版本将给定ZSet之间的差值保存到destination中。该命令在Redi s 6.2及更新版本中才可用。 ➢ ZINCRBY key increment member将memeber元素的score增加increment。 ➢ ZINTER numkeys key [key…]计算给定ZSet的交集。该命令在Redis 6.2及更新版本中才可用。 ➢ ZINTERSTORE destination numkeys key [key…]ZINTER的存储版本将给定ZSet的交集保存到destination中。交集中元素的sc ore是相同元素的score之和。 ➢ ZLEXCOUNT key min max返回ZSet中按字典排序时从min到max之间所有元素的个数。 提示 当向ZSet中添加多个score相等的元素时ZSet就会使用字典顺序 英文字典中字母的排序方式对这些元素进行排序此时就可按字 典顺序来获取指定范围内元素的个数。 ➢ ZPOPMAX key [count]弹出ZSet中score最大的元素。 ➢ BZPOPMAX key [key…] timeoutZPOPMAX的阻塞版本。该命令会阻塞进程直到指定ZSet有元素弹出或超时。 ➢ ZPOPMIN key [count]弹出ZSet中score最小的元素。 ➢ BZPOPMIN key [key…] timeoutZPOPMIN的阻塞版本。该命令会阻塞进程直到指定ZSet有元素弹出或超时。 ➢ ZRANGE key start stop [WITHSCORES]返回ZSet中从start索引到stop索引范围内的元素及score。索引支持负数负数表示 从最后面开始比如-1代表最后一个元素。 ➢ ZRANGEBYLEX key min max [LIMIT offset count]返回ZSet 中按字典排序时从min到max之间的所有元素。 ➢ ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]返回ZSet中score位于min和max之间的所有元素。 ➢ ZRANK key member返回ZSet中指定元素的索引。score最小的元素的索引是0。 ➢ ZREM key member [member…]删除ZSet中一个或多个元素。 ➢ ZREMRANGEBYLEX key min max删除ZSet中按字典排序时从min到max之间的所有元素。 ➢ ZREMRANGEBYRANK key start stop删除ZSet中从start索引到stop索引之间的所有元素。 ➢ ZREMRANGEBYSCORE key min max删除ZSet中score位于min和max之间的所有元素。 ➢ ZREVRANGE key start stop [WITHSCORES]ZRANGE的反向版本。 ➢ ZREVRANGEBYLEX key max min [LIMIT offset count]ZRANGEBYLEX的反向版本。 ➢ ZREVRANGEBYSCORE key max min [WITHSCORES]ZRANGEBYSCORE的反向版本。 ➢ ZREVRANK key memberZRANK的反向版本。score最大的元素的反向索引是0。 ➢ ZSCORE key member获取指定元素的score。 ➢ ZUNION numkeys key [key…]计算给定ZSet的并集。该命令在Redis 6.2及更新版本中才可用。 ➢ ZUNIONSTORE destination numkeys key [key…]ZUNION的存储版本将给定ZSet的并集保存到destination中。 ➢ ZMSCORE key member [member…]获取多个元素的score。该命令在Redis 6.2及更新版本中才可用。
7.Hash相关命令
Hash类型是一个key和value都是String类型的key-value对。Hash类型适合存储对象。每个Hash最多可存储232-1个key-value对。 与Hash相关的常用命令如下。 ➢ HDEL key field [field…]删除Hash对象中一个或多个key-value对。此处的field参数其实代表Hash对象中的key后面提到的f ield参数皆如此。 ➢ HEXISTS key field判断Hash对象中指定的key是否存在。 ➢ HGET key field获取Hash对象中指定key对应的value。 ➢ HGETALL key获取Hash对象中所有的key-value对。 ➢ HINCRBY key field increment为Hash对象中指定的key增加increment。 ➢ HINCRBYFLOAT key field incrementHINCRBY的浮点数版本支持小数。 ➢ HKEYS key获取Hash对象中所有的key。 ➢ HLEN key获取Hash对象中key-value对的数量。 ➢ HMGET key field [field…]HGET的加强版可同时获取多个key对应的value。 ➢ HSET key field value为Hash对象设置一个key-value对。如果field对应的key已经存在新设置的value将会覆盖原有的value。 ➢ HMSET key field value [field value…]HSET的加强版可同时设置多个key-value对。 ➢ HSETNX key field valueHSET的安全版本只有当field对应的key不存在时才能设置成功。 ➢ HSTRLEN key field获取Hash对象中指定key对应的value的字符串长度。 ➢ HVALS key获取Hash对象中所有的value。
8.事务相关命令
Redis事务保证事务内的多条命令会按顺序作为整体执行其他客户端发出的请求绝不可能被插入到事务处理的中间这样可以保证事 务内所有的命令作为一个隔离操作被执行。Redis事务同样具有原子性事务内所有的命令要么全部被执行要么全部被放弃。比如Redis在事务执行过程中遇到数据库宕机假如事务已经执行了一半的命令Redis将会自动回滚这些已经执行过的命令。注意某条命令执行出现错误并不会影响事务的提交。 与事务相关的常用命令如下。 ➢ DISCARD取消事务放弃执行事务块内的所有命令。 ➢ EXEC执行事务。 ➢ MULTI开启事务。 ➢ WATCH key [key…]监视一个或多个key如果在事务执行 之前这些key对应的值被其他命令改动事务会自动中断。 ➢ UNWATCH取消WATCH命令对所有key的监视。
9.Java代码运行示例
记得导入依赖 dependencygroupIdio.lettuce/groupIdartifactIdlettuce-core/artifactId/dependency9.1Redis同步请求代码
package com.example.domain;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;import java.time.Duration;
import java.util.Map;public class Syn {public static void main(String[] args) {load_redis();}private static void load_redis() {RedisURI uri RedisURI.builder().withHost(localhost).withPort(6379).withDatabase(0).withPassword(new char[]{1, 2, 3, 4, 5, 6}).withTimeout(Duration.ofMinutes(5)).build();RedisClient redisClient RedisClient.create(uri);StatefulRedisConnectionString, String connect redisClient.connect();RedisCommandsString, String cmd connect.sync();cmd.set(name,fkjava);cmd.hmset(user, Map.of(name,fkjava,age,25,height,182));cmd.sadd(items,鼠标,要是,钱包);cmd.zadd(test,3.0,java);cmd.zadd(test, ScoredValue.just(2.0,kotlin),ScoredValue.just(2.5,python));connect.close();redisClient.shutdown();}
}9.2Redis异步请求代码
package com.example.domain;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.sync.RedisCommands;import java.time.Duration;
import java.util.Map;
//异步请求
//异步请求
//异步请求
//异步请求
//异步请求
//异步请求
public class ASyn {private RedisClient client;private StatefulRedisConnectionString,String conn;public void init(){RedisURI uri RedisURI.builder().withHost(localhost).withPort(6379).withDatabase(2).withPassword(new char[]{1, 2, 3, 4, 5, 6}).withTimeout(Duration.ofMinutes(5)).build();this.client RedisClient.create(uri);this.conn client.connect();}public void AccessRedis(){
// 创建异步方式RedisAsyncCommandsString, String cmd conn.async();cmd.set(name,fkjava).thenAccept(System.out::println);cmd.hmset(user, Map.of(name,fkjava,age,25,height,182)).thenAccept(System.out::println);cmd.sadd(items,鼠标,要是,钱包).thenAccept(System.out::println);cmd.zadd(test,3.0,java).thenAccept(System.out::println);cmd.zadd(test, ScoredValue.just(2.0,kotlin),ScoredValue.just(2.5,python)).thenAccept(System.out::println);}public void closeResource(){conn.close();client.shutdown();}public static void main(String[] args) {ASyn app new ASyn();app.init();app.AccessRedis();app.closeResource();}
}
9.3Redis反应式请求代码
package com.example.domain;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.reactive.RedisReactiveCommands;import java.time.Duration;
import java.util.Map;
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
public class Reactive {private RedisClient client;private StatefulRedisConnectionString,String conn;public void init(){RedisURI uri RedisURI.builder().withHost(localhost).withPort(6379).withDatabase(3).withPassword(new char[]{1, 2, 3, 4, 5, 6}).withTimeout(Duration.ofMinutes(5)).build();this.client RedisClient.create(uri);this.conn client.connect();}/*** 对于反应式API由于测试时想要立即获取结果因此需要使用block来阻塞县城获取反应式方法的结果。否则你的程序已经退出了但反应式方法搜返回的Mono或Flux中数据还未到来.* 但如果你结合WebFlux使用反应式API你可以直接让你控制器返回Mono或者Flux这样就不需要block了。* 如果前端用的WEbFlux后端用反应式api是很爽的但如果前端用的是普通Spring MVC那就不太理想了。*/public void AccessRedis(){
// 创建反应式RedisReactiveCommandsString, String cmd conn.reactive();System.out.println(cmd.set(name,fkjava).block());System.out.println(cmd.hmset(user, Map.of(name,fkjava,age,25,height,182)).block());System.out.println(cmd.sadd(items,鼠标,要是,钱包).block());System.out.println(cmd.zadd(test,3.0,java).block());System.out.println(cmd.zadd(test, ScoredValue.just(2.0,kotlin),ScoredValue.just(2.5,python)).block());}public void closeResource(){conn.close();client.shutdown();}public static void main(String[] args) {Reactive app new Reactive();app.init();app.AccessRedis();app.closeResource();}
}
10.订阅发布的Redis的Java代码演示
先启动Subscriber1和2的后启动Publisher.java的注意public void subscribed(String channel, long count)的count是表示有几个订阅的意思 Redis对象池的依赖
dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactIdversion2.10.0/version/dependency1.Subscriber.java
package org.crazyit.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;
import java.util.Map;/*** Description:br* 网站: a hrefhttp://www.crazyit.org疯狂Java联盟/abr* Copyright (C), 2001-2022, Yeeku.H.Leebr* This program is protected by copyright laws.br* Program Name:br* Date:br** author Yeeku.H.Lee kongyeeku163.com 公众号: fkbooksbr* version 1.0*/
public class Subscriper
{private RedisClient redisClient;private GenericObjectPoolStatefulRedisPubSubConnectionString, String pool;public void init(){// 1 定义RedisURIvar uri RedisURI.builder().withHost(127.0.0.1).withPort(6379).withDatabase(1).withPassword(new char[]{1, 2, 3, 4, 5,6}).withTimeout(Duration.ofMinutes(5)).build();// 2. 创建RedisClientthis.redisClient RedisClient.create(uri);var conf new GenericObjectPoolConfigStatefulRedisPubSubConnectionString, String();conf.setMaxTotal(20); // 设置允许的最大连接数// 3. 创建连接池对象其中连接由redisClient的connectPubSub方法创建pool ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}public void closeResource(){// 关闭连接池this.pool.close();this.redisClient.shutdown();}public void subscribe() throws Exception{// 从连接池中取出连接StatefulRedisPubSubConnectionString, String conn this.pool.borrowObject();// 4. 创建RedisPubSubCommandsRedisPubSubCommands cmd conn.sync();// 消息到来时肯定是通过监听器来实现的conn.addListener(new RedisPubSubAdapter(){Overridepublic void message(String channel, String message){System.out.printf(从%s收到消息:%s\n, channel, message);}Overridepublic void subscribed(String channel, long count){System.out.println(完成订阅 count);}Overridepublic void unsubscribed(String channel, long count){System.out.println(取消订阅 count);}});// 订阅channelcmd.subscribe(c1, c2);}public static void main(String[] args) throws Exception{Subscriper s new Subscriper();s.init();s.subscribe();// 该程序就只订阅1minThread.sleep(60000);// 5. 关闭资源s.closeResource();}
}
2.subscriber2.java
package org.crazyit.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;/*** Description:br* 网站: a hrefhttp://www.crazyit.org疯狂Java联盟/abr* Copyright (C), 2001-2022, Yeeku.H.Leebr* This program is protected by copyright laws.br* Program Name:br* Date:br** author Yeeku.H.Lee kongyeeku163.com 公众号: fkbooksbr* version 1.0*/
public class Subscriper2
{private RedisClient redisClient;private GenericObjectPoolStatefulRedisPubSubConnectionString, String pool;public void init(){// 1 定义RedisURIvar uri RedisURI.builder().withHost(127.0.0.1).withPort(6379).withDatabase(1).withPassword(new char[]{1, 2, 3, 4, 5,6}).withTimeout(Duration.ofMinutes(5)).build();// 2. 创建RedisClientthis.redisClient RedisClient.create(uri);var conf new GenericObjectPoolConfigStatefulRedisPubSubConnectionString, String();conf.setMaxTotal(20); // 设置允许的最大连接数// 3. 创建连接池对象其中连接由redisClient的connectPubSub方法创建pool ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}public void closeResource(){// 关闭连接池this.pool.close();this.redisClient.shutdown();}public void subscribe() throws Exception{// 从连接池中取出连接StatefulRedisPubSubConnectionString, String conn this.pool.borrowObject();// 4. 创建RedisPubSubCommandsRedisPubSubCommands cmd conn.sync();// 消息到来时肯定是通过监听器来实现的conn.addListener(new RedisPubSubAdapter(){Overridepublic void message(String channel, String message){System.out.printf(从%s收到消息:%s\n, channel, message);}Overridepublic void subscribed(String channel, long count){System.out.println(完成订阅 count);}Overridepublic void unsubscribed(String channel, long count){System.out.println(取消订阅 count);}});// 订阅channelcmd.subscribe(c2);}public static void main(String[] args) throws Exception{Subscriper2 s new Subscriper2();s.init();s.subscribe();// 该程序就只订阅1minThread.sleep(60000);// 5. 关闭资源s.closeResource();}
}
3.Publisher.java
package org.crazyit.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;/*** Description:br* 网站: a hrefhttp://www.crazyit.org疯狂Java联盟/abr* Copyright (C), 2001-2022, Yeeku.H.Leebr* This program is protected by copyright laws.br* Program Name:br* Date:br** author Yeeku.H.Lee kongyeeku163.com 公众号: fkbooksbr* version 1.0*/
public class Publisher
{private RedisClient redisClient;private GenericObjectPoolStatefulRedisPubSubConnectionString, String pool;public void init(){// 1 定义RedisURIvar uri RedisURI.builder().withHost(127.0.0.1).withPort(6379).withDatabase(1).withPassword(new char[]{1, 2, 3, 4, 5,6}).withTimeout(Duration.ofMinutes(5)).build();// 2. 创建RedisClientthis.redisClient RedisClient.create(uri);var conf new GenericObjectPoolConfigStatefulRedisPubSubConnectionString, String();conf.setMaxTotal(20); // 设置允许的最大连接数// 3. 创建连接池对象其中连接由redisClient的connectPubSub方法创建pool ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}public void closeResource(){// 关闭连接池this.pool.close();this.redisClient.shutdown();}public void publish() throws Exception{// 从连接池中取出连接StatefulRedisPubSubConnectionString, String conn this.pool.borrowObject();// 4. 创建RedisPubSubCommandsRedisPubSubCommands cmd conn.sync();// 发布两条消息cmd.publish(c2, 欢迎学习Redis的消息机制);cmd.publish(c1, Redis其实很简单);// 5. 关闭资源this.closeResource();}public static void main(String[] args) throws Exception{Publisher s new Publisher();s.init();s.publish();s.closeResource();}
} 11.杂碎的Redis笔记
★ Lettuce的核心API RedisURI用于封装Redis服务器的URI信息。 RedisClient代表Redis客户端如果连接Cluster模式的Redis则使用RedisClusterClient。 有点类似于redis-cli工具。 StatefulConnectionK,V代表Redis连接的父接口它派生了不少子接口来代表不同的连接。 RedisCommands用于执行Redis命令的接口它的方法几乎覆盖了Redis的所有命令前面介绍的那些命令全部都支持 它的方法名和Redis命令名也是一一对应的肯定一看就会 比如Redis对操作Hash对象提供了hmset命令那RedisCommands就支持hmset()方法 它派生了一个RedisPubSubCommandsK,V子接口用于运行消息发布/订阅的命令。
★ Lettuce编程步骤 使用Lettuce操作Redis的大致步骤如下1定义RedisURI有点类似于数据库的URL再以RedisURI为参数创建RedisClient或RedisClusterClient对象。
2调用RedisClient或RedisClusterClient的connectXxx()方法连接Redis服务器根据所连接的Redis服务器的状态不同该方法返回StatefulRedisXxxConnection连接对象。
3调用连接对象的sync()、async()或reactive()方法创建同步、异步或反应式模式的RedisCommands对象。
4调用RedisCommands执行Redis命令。这一步是变化最多的因为RedisCommands可以执行Redis的全部命令。
5关闭资源。关闭资源时按照惯例“先开后闭”因此先关闭与Redis的连接对象再关闭RedisClient对象。 URI → 创建Client → 建立连接 → 创建RedisCommands → 执行命令 → 关闭资源★ 构建RedisURI
Lettuce提供了如下三种方式来构建RedisURIA. 调用静态的create()方法。这种方式要求把所有的连接信息都写在create()方法的String参数中。该String参数既支持单机模式的Redis也支持集群模式的Redis也支持哨兵模式的Redis。B. 调用Builder来构建。这种构建方式下所有信息都通过Builder对应的方法逐项传入因此可读性最好这也是我所推荐的方式。 C. 调用构造器来构建。这种方式是最不灵活的方式因为它只能传入3个构造器参数通过该方式构建RedisURI之后还需要调用它的setter方法对它进行设置这种方式是最差的一种。★ 从RedisClient到StatefulConnection对象连接 ——获取与Redis服务器的连接
以RedisURI为参数调用RedisClient或RedisClusterClient的create()静态方法即可创建RedisClient或RedisClusterClient对象。
根据Redis运行模式调用RedisClient或RedisClusterClient对象对应的connectXxx()方法获取StatefulConnection对象。▲ StatefulConnection提供如下常用子接口- StatefulRedisConnection最基本的Redis连接。
- StatefulRedisPubSubConnection带消息发布/订阅功能的Redis连接。
- StatufulRedisMasterSlaveConnection主从模式的Redis连接。
- StatefulRedisSentinelConnection哨兵模式的Redis连接。 ★ 从StatefulConnection到RedisXxxCommands对象
调用StatefulRedisXxxConnection连接对象的以下三个方法来创建RedisXxxCommands对象。
sync()创建同步模式的RedisCommands对象。async()创建异步模式的RedisAsyncCommands对象。reactive()创建反应式模式的RedisReactiveCommands对象。
RedisCommands的作用类似于redis-cli.exe工具用于执行各种Redis命令。 其中RedisAsyncCommands是异步版本而RedisReactiveCommands则是反应式版本
★ 使用连接池管理Redis连接
从Redis 6.0开始Redis可支持使用多线程来接收、处理客户端命令因此应用程序可使用连接池来管理Redis连接。
Lettuce连接池支持需要Apache Commons Pool2的支持
接下来即可在程序中通过类似如下代码片段来创建连接池了。
var conf new GenericObjectPoolConfigStatefulRedisConnectionString, String(); conf.setMaxTotal(20); // 设置允许的最大连接数 // 创建连接池对象其中连接由redisClient的connectPubSub方法创建 pool ConnectionPoolSupport.createGenericObjectPool( redisClient::connect, conf);
★ Spring Boot为Redis提供的自动配置
spring-boot-starter-data-redis使用Spring Data Redis对底层Lettuce或Jedis进行了封装。▲ 自动配置Spring Boot会为Redis自动配置RedisConnectionFactory、
SpringBoot支持两种配置连接LettuceJedis。
StringRedisTemplate
ReactiveStringRedisTemplate反应式API因此可将它们注入任意其他组件比如DAO组件。如果配置了自定义的RedisConnectionFactory Spring Boot就不会自动配置RedisConnectionFactory。但RedisTemplate可额外配置很多个只要额外配置的RedisTemplate的id不是redisTemplate
Spring Boot依然会自动配置id为redisTemplate的RedisTemplate。StringRedisTemplate则不同只要你在容器中配置了类型为StringRedisTemplate Bean,自动配置将不再配置它。 ★ Redis配置相关的属性
可通过spring.redis.*开头的属性进行配置连接的服务器该配置属于由RedisProperties类负责处理例如如下配置
spring.redis.host192.168.1.188
spring.redis.port6380
如果你指定了url属性host, port, and password这些属性就会被覆盖如果类加载路径下包含了Apache Commons Pool2依赖库Spring Boot会使用连接池管理连接。可通过spring.redis.lettuce.pool.*开头的属性配置连接池。例如如下两行配置了有关连接池的信息# 指定连接池中最大的活动连接数为20
spring.redis.lettuce.pool.maxActive 20
# 指定连接池中最大的空闲连接数为20
spring.redis.lettuce.pool.maxIdle20 ★ RedisTemplate
RedisTemplate是Spring Data Redis提供的它相当于一个操作Redis数据库的门面类。它提供如下方法来操作数据库
一般用的都是它的子类StringRedisTemplate——相当于它的key、value都是String类型- HK,HV HashOperationsK,HK,HV opsForHash()返回操作Hash对象的HashOperations对象。
- ListOperationsK,V opsForList()返回操作List对象的ListOperations对象。
- SetOperationsK,V opsForSet()返回操作Set对象的SetOperations对象。
- ValueOperationsK,V opsForValue()返回操作String对象的ValueOperations对象。
- ZSetOperationsK,V opsForZSet()返回操作Zset对象的ZSetOperationsK,V 对象。【注意】 程序实际上应该使用StringRedisTemplate来操作Redis数据库。★ RedisTemplate VS RedisCommands
- RedisCommands的做法是它自己为Redis所有命令定义了对应的方法- RedisTemplate对Redis命令进行了分类不同的命令由不同的接口提供支持比如操作List的命令由ListOperations负责提供操作Set的命令则由SetOperations负责提供而RedisTemplate只是提供opsForXxx()方法来返回相应的操作接口。 - RedisTemplate还提供了一些直接操作key的方法例如delete(K key)删key、getExpire(K key)获取key的过期时间、move(K key, int dbIndex)移动key、rename(K oldKey, K newKey)重命名key等方法 ▲ 很明显还是用Spring Bot Data Redis编程更简单。如果你直接用Lettuce编程你需要自行创建RedidUri, RedisClientStatefuleConnection最后才能得到RedisCommand。但如果你用Spring Boot data ReidsSpring Boot可以自动配置RedisTEmplate并将它注入DAO组件因此方便得多。★ Spring Data Redis的功能 DAO接口只需继承CrudRepositorySpring Data Redis能为DAO组件提供实现类。- Spring Data Redis支持方法名关键字查询只不过Redis查询的属性必须是被索引过的索引就是为它建立对应的key这样才能被查询- Spring Data Redis同样支持DAO组件添加自定义的查询方法——通过添加额外的父接口并为额外的父接口提供实现类Spring Data Redis就能该实现类中的方法“移植”到DAO组件中。- Spring Data Redis同样支持Example查询。A. 不支持Query的自定义查询B. 也不支持方法名查询中定义复杂的运算符C. 也不支持Specification查询。★ 方法名关键字查询 Spring Data Redis的方法名关键字查询不如JPA那么强大这是由Redis底层决定Redis并不支持任何查询它是一个简单的key-value数据库因此它获取数据的唯一方式就是根据key获取value。因此它不能支持GreaterThan、LessThan、Like……等复杂关键字它只能支持如下简单的关键字- And例如在接口中可以定义“findByNameAndAge”。- Or例如“findByNameOrAge”。- Is、Equals例如“findByNameIs”、“findByName”、“findByNameEquals”。这种表示相同或相等的关键字不加也行。- Top、First例如“findFirst5Name”、“findTop5ByName”实现查询前5条记录。★ 注解 Spring Data Redis提供了如下两个注解- RedisHash该注解指定将数据类映射到Redis的Hash对象。类似于JPA的Entity。- TimeToLive该注解修饰一个数值类型的属性用于指定该对象的过期时长。Spring Data Redis还提供了如下两个索引化注解- Indexed指定对普通类型的属性建立索引索引化后的属性可用于查询。- GeoIndexed指定对Geo数据地理数据类型的属性建立索引。★ Spring Data Redis的存储机制 - key为books由RedisHash注解指定的value是一个SetSet中元素就是每个Book对象的标识属性值。- key为“books:id值”对应的Hash对象就保存一个一个的持久化对象的全部信息。你的程序保存了几个持久化对象Redis中就有几个key为“books:id值”格式的key-value对。- 每个索引后的属性都会建立对应key。比如你对author属性建立了索引Indexed修饰Spring Data Redis就会在数据库中建立以“books:author:*”开头的key其中*就代表索引属性的每个可能的值。比如你对name属性建立了索引Indexed修饰Spring Data Redis就会在数据库中建立以“books:name:*”开头的key其中*就代表索引属性的每个可能的值。这种索引key对应的value是Set类型该Set的元素就是该key对应的所有实体的id值。- 每个实体都会有一个单独key。books: id值: idx 该key对应的value是Set该Set集合就保存在实体所支持的全部的索引属性key。▲ 假设Spring Data Redis要查询ID为2的Book对象1确定Book类上的RedisHash该注解指定Book对应的key前缀为books2Redis获取key为 “books:2”对应value该value是被查询对象的全部信息。▲ 根据索引属性来查询假设Spring Data Redis要查询name为Python的Book对象1确定Book类上的RedisHash该注解指定Book对应的key前缀为books2 Redis获取key为 books:name:Python所对应的value。3该value返回的就是Set该Set中的每个值都是ID。4遍历第3步中Set里的每个ID然后Redis获取key为 “books:ID”对应value该value是被查询对象的全部信息。