Redis - 5 ( 18000 字 Redis 入门级教程 )

一: 补充知识

1.1 渐进式遍历

Redis 使用 scan 命令以渐进式方式遍历键,避免了直接使用 keys 命令可能引发的阻塞问题。scan 的时间复杂度为 O(1),但需要多次执行才能完成对所有键的遍历,整个过程分步进行,有效减少阻塞风险。首次执行时,scan 从游标 0 开始,当返回的下次游标为 0 时,遍历结束。每次执行 scan 会返回下次游标(cursor)和本次获取的键。不过,虽然 scan 的渐进式遍历解决了阻塞问题,但在遍历期间如果键发生变化(如增加、修改或删除),可能会导致键的重复遍历或遗漏,这一点需要在实际开发中加以考虑。

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
redis 127.0.0.1:6379> scan 0
1) "17"
2)  1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"

在这里插入图片描述

1.2 数据库管理

Redis 提供了几个针对数据库操作的常用命令,包括 dbsize、select、flushdb 和 flushall。接下来将通过具体示例介绍这些命令的常见用法。

1.2.1 切换数据库

许多关系型数据库(如 MySQL)支持在一个实例下存在多个数据库,并通过字符区分数据库名称,而 Redis 则使用数字来区分数据库。Redis 默认配置中提供 16 个数据库,默认处于 0 号数据库。通过 select 0 可以切换到第一个数据库,而 select 15 则切换到最后一个数据库。不同数据库之间的数据是完全独立的,各自保存各自的键值对,互不冲突。

虽然 Redis 支持多数据库,但随着版本升级,官方并不推荐使用这一特性。如果需要完全隔离的两套键值对,更好的方案是维护多个 Redis 实例,而不是在一个实例中使用多个数据库。这是因为 Redis 对多数据库的支持较为有限,同时无论是否使用多数据库,Redis 都采用单线程模型,多个数据库之间仍需排队等待命令执行。此外,使用多数据库会增加开发、调试和运维的复杂性。因此,在实际应用中,始终使用默认的 0 号数据库通常是更好的选择。

select dbIndex

在这里插入图片描述

1.2.2 清除数据库

flushdb 和 flushall 命令用于清除数据库,区别在于 flushdb 仅清除当前数据库的数据,而 flushall 会清除所有数据库的数据。在实际应用中,除非必要,永远不要在生产环境中执行清除数据的操作,否则可能会导致严重后果。

二: 使用 Java 操作 redis 的客户端

在 Java 中操作 Redis 的客户端有很多,其中最常用且知名的是 Jedis。首先创建一个 Maven 项目,并将 Jedis 的依赖添加到 pom.xml 文件中:

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.2</version>
</dependency>

2.1 配置端口转发

如果 Redis 服务器安装在云服务器上,而代码运行在本地主机上,为了让本地主机访问 Redis,需要在云服务器后台(如防火墙或安全组)开放 Redis 的端口到公网。但这种操作非常危险,因为可能会被黑客利用 Redis 端口入侵。为了解决这一问题,可以使用端口转发的方式,将服务器的 Redis 端口映射到本地。在 Xshell 中,可以通过相应配置实现这一功能,从而在保证安全的前提下访问远程 Redis 服务。

步骤操作说明
1右键选择云服务器的会话,点击“属性”。
2进入“隧道”选项卡,配置转发规则。
在这里插入图片描述

在这里插入图片描述

接着使用该会话连接服务器,此时访问本地的 8888 端口就相当于访问服务器的 6379 端口。需要注意的是,Xshell 必须与服务器保持连接状态,映射才能生效。

2.2 连接 Redis Server

步骤操作说明
1使用 JedisPool 描述 Redis 服务器的位置,并通过 URL 表示。
2使用 getResource 方法与 Redis 服务器建立连接。
3连接使用完毕后需要调用 close 方法关闭,或者直接使用 try 自动关闭连接。
4通过 ping 方法检测连接是否正确建立。
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");try (Jedis jedis = jedisPool.getResource()) {String ping = jedis.ping(); // 这个方法会返回 PONGSystem.out.println(ping); // 输出 PONG
}

在这里插入图片描述

这个报错不影响使用,忽略即可,下面讲解一下 Java 操作 redis 的客户端的基本操作

2.3 set 和 get

当 key 不存在时,使用 get 方法获取的 value 将为 null。

public static void main(String[] args) {JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");try (Jedis jedis = jedisPool.getResource()) {testGetSet(jedis);jedis.flushDB(); // 清空数据库}
}private static void testGetSet(Jedis jedis) {jedis.set("key1", "value1"); // 设置 key1 的值为 value1jedis.set("key2", "value2"); // 设置 key2 的值为 value2String value1 = jedis.get("key1");System.out.println(value1); // 输出: value1String value2 = jedis.get("key2");System.out.println(value2); // 输出: value2String valueNull = jedis.get("noSuchKey");System.out.println(valueNull); // 输出: null
}

2.4 exists 和 del

del 方法可以删除多个 key,以可变参数列表的形式传入,返回值表示实际删除的 key 的数量。

private static void testExistsAndDel(Jedis jedis) {jedis.set("key1", "value"); // 设置 key1 的值为 valuejedis.set("key2", "value"); // 设置 key2 的值为 valuejedis.set("key3", "value"); // 设置 key3 的值为 valueboolean ret = jedis.exists("key1");System.out.println(ret); // 输出: true (key1 存在)long n = jedis.del("key1");System.out.println(n); // 输出: 1 (成功删除了 1 个 key)ret = jedis.exists("key1");System.out.println(ret); // 输出: false (key1 已被删除)n = jedis.del("key2", "key3");System.out.println(n); // 输出: 2 (成功删除了 2 个 key)ret = jedis.exists("key2");System.out.println(ret); // 输出: false (key2 已被删除)
}

2.5 keys

private static void testKeys(Jedis jedis) {jedis.set("key1", "value1"); // 设置 key1 的值为 value1jedis.set("key2", "value2"); // 设置 key2 的值为 value2jedis.set("key3", "value3"); // 设置 key3 的值为 value3jedis.set("myKey", "value4"); // 设置 myKey 的值为 value4Set<String> keys = jedis.keys("*");System.out.println(keys); // 输出: [key1, key2, key3, myKey] (匹配所有键)keys = jedis.keys("key?");System.out.println(keys); // 输出: [key1, key2, key3] (匹配 key 后面跟一个字符的键)
}

2.6 expire 和 ttl

使用 setex 方法可以在设置 key 的同时指定其过期时间,过期时间的单位为秒。

private static void testExpireAndTTL(Jedis jedis) {jedis.setex("key", 60, "value"); // 设置 key 的值为 value,并指定过期时间为 60 秒long ttl = jedis.ttl("key");System.out.println(ttl); // 输出: 剩余的过期时间,单位为秒(如:60,表示还有 60 秒过期)
}

2.7 type

private static void testType(Jedis jedis) {jedis.set("key1", "value"); // 设置 key1 的值为 valueSystem.out.println(jedis.type("key1")); // 输出: string (key1 是字符串类型)jedis.lpush("key2", "a", "b", "c"); // 向 key2 的列表中依次从左插入 a, b, cSystem.out.println(jedis.type("key2")); // 输出: list (key2 是列表类型)jedis.hset("key3", "name", "zhangsan"); // 设置 key3 的哈希字段 name 为 zhangsanSystem.out.println(jedis.type("key3")); // 输出: hash (key3 是哈希类型)jedis.sadd("key4", "111", "222", "333"); // 向 key4 的集合中添加 111, 222, 333System.out.println(jedis.type("key4")); // 输出: set (key4 是集合类型)jedis.zadd("key5", 1, "aaa"); // 向 key5 的有序集合中添加元素 aaa,分值为 1System.out.println(jedis.type("key5")); // 输出: zset (key5 是有序集合类型)
}

2.8 mget 和 mset

private static void testMSetAndMGet(Jedis jedis) {jedis.mset("key1", "value1", "key2", "value2", "key3", "value3"); // 批量设置 key-value 键值对List<String> values = jedis.mget("key1", "key2", "key3"); // 批量获取 key1, key2, key3 的值System.out.println(values); // 输出: [value1, value2, value3] (返回对应键的值列表)
}

2.9 append

private static void testAppend(Jedis jedis) {jedis.append("key", "aaa"); // 向 key 的值后追加字符串 aaaString value = jedis.get("key");System.out.println(value); // 输出: aaa (key 的当前值)jedis.append("key", "bbb"); // 向 key 的值后追加字符串 bbbvalue = jedis.get("key");System.out.println(value); // 输出: aaabbb (key 的当前值)
}

2.10 getrange 和 setrange

需要注意 getrange 方法的区间是闭区间

private static void testGetRangeAndSetRange(Jedis jedis) {jedis.set("key", "abcdefg"); // 设置 key 的值为 "abcdefg"String value = jedis.getrange("key", 1, 4); // 获取 key 的值中从索引 1 到 4 的子串(闭区间)System.out.println(value); // 输出: bcdejedis.setrange("key", 0, "xyz"); // 从索引 0 开始,用 "xyz" 替换 key 的值部分内容value = jedis.get("key");System.out.println(value); // 输出: xyzdefg
}

2.11 setnx

private static void testSetnx(Jedis jedis) {long n = jedis.setnx("key", "value"); // 如果 key 不存在,则设置 key 的值为 "value"System.out.println(n); // 输出: 1 (key 不存在,设置成功)String value = jedis.get("key");System.out.println(value); // 输出: value (当前 key 的值)n = jedis.setnx("key", "value2"); // 如果 key 已存在,不会修改值System.out.println(n); // 输出: 0 (key 已存在,设置失败)value = jedis.get("key");System.out.println(value); // 输出: value (key 的值仍为原来的值)
}

2.12 psetex

通过 pttl 获取的结果不一定正好是 1000 毫秒,因为 pttl 本身存在时间开销。

private static void testPsetexAndPttl(Jedis jedis) {jedis.psetex("key", 1000, "value"); // 设置 key 的值为 "value",并指定过期时间为 1000 毫秒long ttl = jedis.pttl("key"); // 获取 key 剩余的过期时间(单位:毫秒)System.out.println(ttl); // 输出: 一个接近 1000 的数值(因为存在时间开销,不一定正好是 1000)
}

2.13 incr 和 decr

private static void testIncrAndDecr(Jedis jedis) {jedis.set("key", "0"); // 设置 key 的初始值为 "0"jedis.incr("key"); // 将 key 的值自增 1System.out.println(jedis.get("key")); // 输出: 1 (当前 key 的值)jedis.decr("key"); // 将 key 的值自减 1System.out.println(jedis.get("key")); // 输出: 0 (当前 key 的值)
}

2.14 incrby 和 decrby

private static void testIncrByAndDecrBy(Jedis jedis) {jedis.set("key", "0"); // 设置 key 的初始值为 "0"jedis.incrBy("key", 10); // 将 key 的值增加 10System.out.println(jedis.get("key")); // 输出: 10 (当前 key 的值)jedis.decrBy("key", 5); // 将 key 的值减少 5System.out.println(jedis.get("key")); // 输出: 5 (当前 key 的值)
}

2.15 lpush 和 lpop

private static void testLpushAndLpop(Jedis jedis) {long n = jedis.lpush("key", "1", "2", "3", "4"); // 从左侧依次插入 4, 3, 2, 1System.out.println(n); // 输出: 4 (列表中元素的总数量)String value = jedis.lpop("key"); // 从左侧弹出第一个元素System.out.println(value); // 输出: 4 (第一个弹出的元素)value = jedis.lpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 3value = jedis.lpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 2value = jedis.lpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 1value = jedis.lpop("key"); // 列表为空时,再次弹出System.out.println(value); // 输出: null (列表为空)
}

2.16 rpush 和 rpop

private static void testRpushAndRpop(Jedis jedis) {long n = jedis.rpush("key", "1", "2", "3", "4"); // 从右侧依次插入 1, 2, 3, 4System.out.println(n); // 输出: 4 (列表中元素的总数量)String value = jedis.rpop("key"); // 从右侧弹出第一个元素System.out.println(value); // 输出: 4 (第一个弹出的元素)value = jedis.rpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 3value = jedis.rpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 2value = jedis.rpop("key"); // 弹出下一个元素System.out.println(value); // 输出: 1value = jedis.rpop("key"); // 列表为空时,再次弹出System.out.println(value); // 输出: null (列表为空)
}

2.17 lrange

private static void testLrange(Jedis jedis) {jedis.rpush("key", "1", "2", "3", "4"); // 从右侧依次插入 1, 2, 3, 4List<String> values = jedis.lrange("key", 1, 3); // 获取列表中从索引 1 到 3 的元素(闭区间)System.out.println(values); // 输出: [2, 3, 4] (索引范围内的元素)
}

2.18 blpop

blpop 返回的结果是一个二元组形式的 List,其中索引 [0] 表示 key,索引 [1] 表示 value。将超时时间设置为 0 表示阻塞等待,直到有数据可弹出。在执行 blpop 的同时,可以通过另一个 redis-cli 客户端插入数据,便可实时查看 blpop 的返回结果。

private static void testBLpop(Jedis jedis) {while (true) {List<String> values = jedis.blpop(0, "key"); // 阻塞等待,从列表 key 中弹出第一个元素System.out.println(values); // 输出: [key, value] (返回包含 key 和弹出的值的二元组)}
}

2.19 brpop

private static void testBRpop(Jedis jedis) {System.out.println("开始调用 brpop"); // 提示 brpop 调用开始while (true) {List<String> values = jedis.brpop(0, "key"); // 阻塞等待,从列表 key 中从右侧弹出元素System.out.println(values); // 输出: [key, value] (返回包含 key 和弹出的值的二元组)}
}

2.20 lindex

private static void testLindex(Jedis jedis) {jedis.rpush("key", "1", "2", "3", "4"); // 从右侧依次插入 1, 2, 3, 4String value = jedis.lindex("key", 2); // 获取列表 key 中索引为 2 的元素System.out.println(value); // 输出: 3 (索引 2 对应的元素)
}

2.21linsert

linsert 方法通过指定插入位置标识 ListPosition.BEFORE 或 ListPosition.AFTER,决定新元素是插入到目标元素之前还是之后。

private static void testLinsert(Jedis jedis) {jedis.rpush("key", "a", "b", "c", "d"); // 从右侧依次插入 a, b, c, djedis.linsert("key", ListPosition.BEFORE, "c", "100"); // 在元素 c 之前插入 100List<String> values = jedis.lrange("key", 0, -1); // 获取列表 key 中所有元素System.out.println(values); // 输出: [a, b, 100, c, d] (列表中插入后的结果)
}

2.22 llen

private static void testLlen(Jedis jedis) {jedis.rpush("key", "a", "b", "c", "d"); // 从右侧依次插入 a, b, c, dlong n = jedis.llen("key"); // 获取列表 key 的长度System.out.println(n); // 输出: 4 (列表中元素的总数量)
}

2.23 hset 和 hget

private static void testHsetAndHget(Jedis jedis) {jedis.hset("key", "name", "zhangsan"); // 设置哈希表 key 中字段 name 的值为 zhangsanjedis.hset("key", "age", "20"); // 设置哈希表 key 中字段 age 的值为 20String name = jedis.hget("key", "name"); // 获取哈希表 key 中字段 name 的值System.out.println(name); // 输出: zhangsanString age = jedis.hget("key", "age"); // 获取哈希表 key 中字段 age 的值System.out.println(age); // 输出: 20
}

2.24 hexists 和 hdel

private static void testHexistsAndHdel(Jedis jedis) {jedis.hset("key", "name", "zhangsan"); // 设置哈希表 key 中字段 name 的值为 zhangsanboolean ok = jedis.hexists("key", "name"); // 检查哈希表 key 中是否存在字段 nameSystem.out.println(ok); // 输出: true (字段 name 存在)jedis.hdel("key", "name"); // 删除哈希表 key 中字段 nameok = jedis.hexists("key", "name"); // 再次检查哈希表 key 中是否存在字段 nameSystem.out.println(ok); // 输出: false (字段 name 已被删除)
}

2.25 hkeys 和 hvals

private static void testHkeysAndHvalues(Jedis jedis) {jedis.hset("key", "name", "zhangsan"); // 设置哈希表 key 中字段 name 的值为 zhangsanjedis.hset("key", "age", "20"); // 设置哈希表 key 中字段 age 的值为 20Set<String> keys = jedis.hkeys("key"); // 获取哈希表 key 中所有字段名System.out.println(keys); // 输出: [name, age] (哈希表中的字段名集合)List<String> values = jedis.hvals("key"); // 获取哈希表 key 中所有字段的值System.out.println(values); // 输出: [zhangsan, 20] (哈希表中的字段值集合)
}

2.26 hmget

private static void testHmget(Jedis jedis) {jedis.hset("key", "name", "zhangsan"); // 设置哈希表 key 中字段 name 的值为 zhangsanjedis.hset("key", "age", "20"); // 设置哈希表 key 中字段 age 的值为 20List<String> values = jedis.hmget("key", "name", "age"); // 批量获取哈希表 key 中字段 name 和 age 的值System.out.println(values); // 输出: [zhangsan, 20] (字段对应的值集合)
}

2.27 hlen

private static void testHlen(Jedis jedis) {jedis.hset("key", "name", "zhangsan"); // 设置哈希表 key 中字段 name 的值为 zhangsanjedis.hset("key", "age", "20"); // 设置哈希表 key 中字段 age 的值为 20long n = jedis.hlen("key"); // 获取哈希表 key 中字段的数量System.out.println(n); // 输出: 2 (字段的总数量)
}

2.28 hincrby 和 hincrbyfloat

private static void testHIncrByAndIncrByFloat(Jedis jedis) {jedis.hset("key", "age", "20"); // 设置哈希表 key 中字段 age 的值为 20long n = jedis.hincrBy("key", "age", 10); // 将哈希表 key 中字段 age 的值增加 10System.out.println(n); // 输出: 30 (增加后的值)String value = jedis.hget("key", "age"); // 获取哈希表 key 中字段 age 的值System.out.println(value); // 输出: 30double dn = jedis.hincrByFloat("key", "age", 0.5); // 将哈希表 key 中字段 age 的值增加 0.5System.out.println(dn); // 输出: 30.5 (增加后的值)value = jedis.hget("key", "age"); // 再次获取哈希表 key 中字段 age 的值System.out.println(value); // 输出: 30.5
}

2.29 sadd 和 smembers

private static void testSaddAndSmembers(Jedis jedis) {jedis.sadd("key", "aaa", "bbb", "ccc"); // 向集合 key 中添加元素 aaa, bbb, cccSet<String> members = jedis.smembers("key"); // 获取集合 key 中的所有成员System.out.println(members); // 输出: [aaa, bbb, ccc] (集合中的所有成员,顺序可能无序)
}

2.30 srem 和 sismember

private static void testSremAndSismember(Jedis jedis) {jedis.sadd("key", "aaa", "bbb", "ccc"); // 向集合 key 中添加元素 aaa, bbb, cccboolean ok = jedis.sismember("key", "aaa"); // 检查集合 key 中是否包含元素 aaaSystem.out.println(ok); // 输出: true (aaa 存在于集合中)long n = jedis.srem("key", "aaa", "bbb"); // 从集合 key 中删除元素 aaa 和 bbbSystem.out.println(n); // 输出: 2 (成功删除的元素个数)ok = jedis.sismember("key", "aaa"); // 再次检查集合 key 中是否包含元素 aaaSystem.out.println(ok); // 输出: false (aaa 已被删除)
}

2.31 scard

private static void testScard(Jedis jedis) {jedis.sadd("key", "aaa", "bbb", "ccc"); // 向集合 key 中添加元素 aaa, bbb, ccclong n = jedis.scard("key"); // 获取集合 key 中的元素数量System.out.println(n); // 输出: 3 (集合中元素的总数量)
}

2.32 sinter

private static void testSinter(Jedis jedis) {jedis.sadd("key1", "aaa", "bbb", "ccc"); // 向集合 key1 中添加元素 aaa, bbb, cccjedis.sadd("key2", "aaa", "bbb", "ddd"); // 向集合 key2 中添加元素 aaa, bbb, dddSet<String> results = jedis.sinter("key1", "key2"); // 获取 key1 和 key2 的交集System.out.println(results); // 输出: [aaa, bbb] (两个集合的交集元素)
}

2.33 sunion

private static void testSunion(Jedis jedis) {jedis.sadd("key1", "aaa", "bbb", "ccc"); // 向集合 key1 中添加元素 aaa, bbb, cccjedis.sadd("key2", "aaa", "bbb", "ddd"); // 向集合 key2 中添加元素 aaa, bbb, dddSet<String> results = jedis.sunion("key1", "key2"); // 获取 key1 和 key2 的并集System.out.println(results); // 输出: [aaa, bbb, ccc, ddd] (两个集合的并集元素)
}

2.34 sdiff

private static void testSdiff(Jedis jedis) {jedis.sadd("key1", "aaa", "bbb", "ccc"); // 向集合 key1 中添加元素 aaa, bbb, cccjedis.sadd("key2", "aaa", "bbb", "ddd"); // 向集合 key2 中添加元素 aaa, bbb, dddSet<String> results = jedis.sdiff("key1", "key2"); // 获取 key1 和 key2 的差集 (key1 中有但 key2 中没有的元素)System.out.println(results); // 输出: [ccc] (key1 中独有的元素)
}

2.35 zadd 和 zrange

private static void testZaddAndZrange(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70List<String> members = jedis.zrange("key", 0, 4); // 获取 key 中索引范围 0 到 4 的成员System.out.println(members); // 输出: [刘备, 关羽, 典韦, 赵云, 吕布] (按照分值从低到高排序的成员)List<Tuple> membersWithScore = jedis.zrangeWithScores("key", 0, 4); // 获取 key 中索引范围 0 到 4 的成员及其分值System.out.println(membersWithScore); // 输出: [刘备=70.0, 关羽=92.0, 典韦=95.0, 赵云=98.0, 吕布=100.0]
}

2.36 zrem 和 zcard

private static void testZremAndZcard(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70long n = jedis.zcard("key"); // 获取有序集合 key 中的成员数量System.out.println(n); // 输出: 5 (集合中总的成员数量)n = jedis.zrem("key", "吕布", "赵云"); // 从有序集合 key 中移除成员 吕布 和 赵云System.out.println(n); // 输出: 2 (成功移除的成员数量)n = jedis.zcard("key"); // 再次获取有序集合 key 中的成员数量System.out.println(n); // 输出: 3 (移除成员后的总数量)
}

2.37 zcount

private static void testZcount(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70long n = jedis.zcount("key", 92, 98); // 获取分值在 92 到 98 范围内的成员数量,闭区间System.out.println(n); // 输出: 3 (关羽、典韦、赵云 分值在该范围内)
}

2.38 zpopmax 和 zpopmin

private static void testZpopmaxAndZpopmin(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70Tuple tuple = jedis.zpopmax("key"); // 弹出有序集合 key 中分值最高的成员System.out.println(tuple); // 输出: 吕布=100.0 (分值最高的成员及其分值)tuple = jedis.zpopmin("key"); // 弹出有序集合 key 中分值最低的成员System.out.println(tuple); // 输出: 刘备=70.0 (分值最低的成员及其分值)
}

2.39 zrank

private static void testZrank(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70long n = jedis.zrank("key", "赵云"); // 获取成员 赵云 在有序集合 key 中的排名(从低到高)System.out.println(n); // 输出: 3 (赵云 的排名,从 0 开始)n = jedis.zrevrank("key", "赵云"); // 获取成员 赵云 在有序集合 key 中的排名(从高到低)System.out.println(n); // 输出: 1 (赵云 的排名,从 0 开始)
}

2.40 zscore

private static void testZscore(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100jedis.zadd("key", 98, "赵云"); // 向有序集合 key 中添加成员 赵云,分值为 98jedis.zadd("key", 95, "典韦"); // 向有序集合 key 中添加成员 典韦,分值为 95jedis.zadd("key", 92, "关羽"); // 向有序集合 key 中添加成员 关羽,分值为 92jedis.zadd("key", 70, "刘备"); // 向有序集合 key 中添加成员 刘备,分值为 70double score = jedis.zscore("key", "赵云"); // 获取成员 赵云 在有序集合 key 中的分值System.out.println(score); // 输出: 98.0 (赵云 的分值)
}

2.41 zincrby

private static void testZincrby(Jedis jedis) {jedis.zadd("key", 100, "吕布"); // 向有序集合 key 中添加成员 吕布,分值为 100double n = jedis.zincrby("key", 10, "吕布"); // 增加成员 吕布 的分值 10System.out.println(n); // 输出: 110.0 (吕布 的新分值)n = jedis.zincrby("key", -20, "吕布"); // 减少成员 吕布 的分值 20System.out.println(n); // 输出: 90.0 (吕布 的新分值)
}

2.42 zinterstore

private static void testZinterstore(Jedis jedis) {jedis.zadd("key1", 100, "吕布"); // 向有序集合 key1 中添加成员 吕布,分值为 100jedis.zadd("key1", 98, "赵云"); // 向有序集合 key1 中添加成员 赵云,分值为 98jedis.zadd("key1", 95, "典韦"); // 向有序集合 key1 中添加成员 典韦,分值为 95jedis.zadd("key2", 100, "吕布"); // 向有序集合 key2 中添加成员 吕布,分值为 100jedis.zadd("key2", 98, "赵云"); // 向有序集合 key2 中添加成员 赵云,分值为 98jedis.zadd("key2", 92, "关羽"); // 向有序集合 key2 中添加成员 关羽,分值为 92long n = jedis.zinterstore("key3", "key1", "key2"); // 将 key1 和 key2 的交集存储到 key3 中System.out.println(n); // 输出: 2 (交集中成员的数量)List<Tuple> tuples = jedis.zrangeWithScores("key3", 0, -1); // 获取 key3 中的所有成员及其分值System.out.println(tuples); // 输出: [赵云=196.0, 吕布=200.0] (交集成员及其分值)
}

2.43 zunionstore

private static void testZunionstore(Jedis jedis) {jedis.zadd("key1", 100, "吕布"); // 向有序集合 key1 中添加成员 吕布,分值为 100jedis.zadd("key1", 98, "赵云"); // 向有序集合 key1 中添加成员 赵云,分值为 98jedis.zadd("key1", 95, "典韦"); // 向有序集合 key1 中添加成员 典韦,分值为 95jedis.zadd("key2", 100, "吕布"); // 向有序集合 key2 中添加成员 吕布,分值为 100jedis.zadd("key2", 98, "赵云"); // 向有序集合 key2 中添加成员 赵云,分值为 98jedis.zadd("key2", 92, "关羽"); // 向有序集合 key2 中添加成员 关羽,分值为 92long n = jedis.zunionstore("key3", "key1", "key2"); // 将 key1 和 key2 的并集存储到 key3 中System.out.println(n); // 输出: 4 (并集中成员的数量)List<Tuple> tuples = jedis.zrangeWithScores("key3", 0, -1); // 获取 key3 中的所有成员及其分值System.out.println(tuples); // 输出: [典韦=95.0, 关羽=92.0, 赵云=196.0, 吕布=200.0] (并集成员及其分值)
}

三: 访问集群

使用 JedisCluster 类可以访问 Redis 集群,替代单节点模式下使用的 Jedis 类。在创建 JedisCluster 实例时,需要将多个节点的地址配置进去。JedisCluster 提供的方法与 Jedis 基本一致,都与 Redis 命令一一对应,具体使用细节此处不再演示。

public static void main(String[] args) {// 创建一个存储 Redis 集群节点的集合Set<HostAndPort> nodes = new HashSet<>();nodes.add(new HostAndPort("172.30.0.101", 6379));nodes.add(new HostAndPort("172.30.0.102", 6379));nodes.add(new HostAndPort("172.30.0.103", 6379));nodes.add(new HostAndPort("172.30.0.104", 6379));nodes.add(new HostAndPort("172.30.0.105", 6379));nodes.add(new HostAndPort("172.30.0.106", 6379));nodes.add(new HostAndPort("172.30.0.107", 6379));nodes.add(new HostAndPort("172.30.0.108", 6379));nodes.add(new HostAndPort("172.30.0.109", 6379));// 创建 JedisCluster 实例并执行操作try (JedisCluster jedisCluster = new JedisCluster(nodes)) {jedisCluster.set("k1", "111"); // 设置键 k1 的值为 111String value = jedisCluster.get("k1"); // 获取键 k1 的值System.out.println(value); // 输出: 111}
}

注意,由于代码需要访问整个 Redis 集群,Windows 主机无法直接访问 Docker 容器的 IP 地址,因此无法在 Windows 上直接运行程序。需要将程序打包成 JAR 文件,上传到 Linux 环境中,并在 Linux 上运行程序以实现对 Redis 集群的访问。

java -jar [jar包名]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502798.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

22408操作系统期末速成/复习(考研0基础上手)

第一部分:计算题&#xff1a; 考察范围&#xff1a;&#xff08;标红的是重点考&#xff09; 第一章&#xff1a;CPU利用率&#xff1a; 第二章&#xff1a; 进程调度算法&#xff08;需要注意不同调度算法的优先级和题目中给出的是否可以抢占【分为可抢占和不可抢占&#xff…

AI在电子制造中的应用:预测质量控制

一、 电子制造中存在的质量问题 电子制造过程中&#xff0c;由于生产工艺复杂、材料种类繁多、生产环境要求高等因素&#xff0c;可能会出现各种质量问题。 常见质量问题如下&#xff1a; 1. 空焊 原因&#xff1a;锡膏活性较弱、钢网开孔不佳、铜铂间距过大或大铜贴小元件、…

如何通过API实现淘宝商品评论数据抓取?item_review获取淘宝商品评论

前几天一个好朋友要我帮忙抓一下淘宝商品的评论数据&#xff0c;获取淘宝评论数据可以帮忙商家们做好市场调研&#xff0c;对自己的产品进行升级&#xff0c;从而更好地获取市场。我将详细爬取方法封装成API&#xff0c;以供方便调用。 item_review-获得淘宝商品评论 响应示例…

springboot550乐乐农产品销售系统(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统乐乐农产品销售系统信息管理难度大&#xff0c;容错率低&…

百度贴吧的ip属地什么意思?怎么看ip属地

在数字化时代&#xff0c;IP地址不仅是网络设备的唯一标识符&#xff0c;更承载着用户的网络身份与位置信息。百度贴吧作为广受欢迎的社交平台&#xff0c;也遵循相关规定&#xff0c;在用户个人主页等位置展示账号IP属地信息。那么&#xff0c;百度贴吧的IP属地究竟意味着什么…

[读书日志]从零开始学习Chisel 第一篇:书籍介绍,Scala与Chisel概述,Scala安装运行(敏捷硬件开发语言Chisel与数字系统设计)

简介&#xff1a;从20世纪90年代开始&#xff0c;利用硬件描述语言和综合技术设计实现复杂数字系统的方法已经在集成电路设计领域得到普及。随着集成电路集成度的不断提高&#xff0c;传统硬件描述语言和设计方法的开发效率低下的问题越来越明显。近年来逐渐崭露头角的敏捷化设…

element-plus大版本一样,但是小版本不一样导致页面出bug

npm 的版本 node的版本 npm的源这些都一样&#xff0c;但是效果不一样 发现是element的包版本不一样导致的 2.9.1与2.8.1的源是不一样的&#xff0c;导致页面出bug;

【网络协议】开放式最短路径优先协议OSPF详解(一)

OSPF 是为取代 RIP 而开发的一种无类别的链路状态路由协议&#xff0c;它通过使用区域划分以实现更好的可扩展性。 文章目录 链路状态路由协议OSPF 的工作原理OSPF 数据包类型Dijkstra算法、管理距离与度量值OSPF的管理距离OSPF的度量值 链路状态路由协议的优势拓扑结构路由器O…

《数据结构》期末考试测试题【中】

《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为&#xff1f;22. 单链表的存储密度比1&#xff1f;23.单链表的那些操作的效率受链表长度的影响&#xff1f;24.顺序表中某元素的地址为&#xff1f;25.m叉树第K层的结点数为&#xff1f;26. 在双向循环链表某节点…

华为数通考试模拟真题(附带答案解析)题库领取

【多选题】 管理员想要更新华为路由器的VRP版本&#xff0c;则正确的方法有? A管理员把路由器配置为FTP服务器&#xff0c;通过FTP来传输VRP软件 B:管理员把路由器置为FTP客户端&#xff0c;通过FTP来传输VRP软件 C:管理员把路由器配置为TFTP客户端&#xff0c;通过TFTP来传…

Linux:操作系统不朽的传说

操作系统是计算机的灵魂&#xff0c;它掌控着计算机的硬件和软件资源&#xff0c;为用户和应用程序提供了一个稳定、高效、安全的运行环境。 在众多操作系统中&#xff0c;Linux 的地位举足轻重。它被广泛应用于服务器、云计算、物联网、嵌入式设备等领域。Linux 的成功离不开…

前端(API)学习笔记(CLASS 4):进阶

1、日期对象 日期对象&#xff1a;用来表示事件的对象 作用&#xff1a;可以得到当前系统时间 1、实例化 在代码中发现了new关键字&#xff0c;一般将这个操作称为实例化 创建一个时间对象并获取时间 获得当前时间 const datenew Date() 使用日志查看&#xff0c;得到的…

【USRP】教程:在Macos M1(Apple芯片)上安装UHD驱动(最正确的安装方法)

Apple芯片 前言安装Homebrew安装uhd安装gnuradio使用b200mini安装好的路径下载固件后续启动频谱仪功能启动 gnu radio关于博主 前言 请参考本文进行安装&#xff0c;好多人买了Apple芯片的电脑&#xff0c;这种情况下&#xff0c;可以使用UHD吗&#xff1f;答案是肯定的&#…

SAP 01-初识AMDP(ABAP-Managed Database Procedure)

1. 什么是AMDP(ABAP-Managed Database Procedure) 1.&#xff09;AMDP - ABAP管理数据库程序&#xff0c;是一种程序&#xff0c;我们可以使用SQLSCRIPT在AMDP内部编写代码&#xff0c;SQLSCRIPT是一种与SQL脚本相同的数据库语言&#xff0c;这种语言易于理解和编码。 将AM…

智能客户服务:科技如何重塑客户服务体验

在数字化时代&#xff0c;客户对于服务的需求和期望在不断演变。传统的客户服务模式已经难以满足现代消费者对于即时性、个性化和高效性的追求。随着人工智能、大数据、云计算等先进技术的蓬勃发展&#xff0c;智能客户服务应运而生&#xff0c;不仅重塑了客户服务的体验&#…

[论文笔记]Representation Learning with Contrastive Predictive Coding

引言 今天带来论文 Representation Learning with Contrastive Predictive Coding的笔记。 提出了一种通用的无监督学习方法从高维数据中提取有用表示&#xff0c;称为对比预测编码(Contrastive Predictive Coding,CPC)。使用了一种概率对比损失&#xff0c; 通过使用负采样使…

Kafka 消费者专题

目录 消费者消费者组消费方式消费规则独立消费主题代码示例&#xff08;极简&#xff09;代码示例&#xff08;独立消费分区&#xff09; offset自动提交代码示例&#xff08;自动提交&#xff09;手动提交代码示例&#xff08;同步&#xff09;代码示例&#xff08;异步&#…

【踩坑指南2.0 2025最新】Scala中如何在命令行传入参数以运行主函数

这个地方基本没有任何文档记录&#xff0c;在学习的过程中屡屡碰壁&#xff0c;因此记录一下这部分的内容&#xff0c;懒得看可以直接跳到总结看结论。 踩坑步骤 首先来看看书上让我们怎么写&#xff1a; //main.scala object Start {def main(args:Array[String]) {try {v…

数据分析思维(七):分析方法——群组分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python&#xff0c;更重要的是数据分析思维。没有数据分析思维和业务知识&#xff0c;就算拿到一堆数据&#xff0c;也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》&#xff0c;本文内容就是提取…

CSS 之 position 定位属性详解

CSS系列文章目录 CSS 之 display 布局属性详解 CSS 之 position 定位属性详解一文搞懂flex布局 【弹性盒布局】 文章目录 CSS系列文章目录一、前言二、静态定位&#xff1a;position:static&#xff1b;二、相对定位&#xff1a;position:relative三、绝对定位&#xff1a;pos…