Jedis 操作 Redis 数据结构全攻略
- 一 . 认识 RESP
- 二 . 前置操作
- 2.1 创建项目
- 2.2 关于开放 Redis 端口的问题
- 2.2.1 端口转发?
- 2.2.2 端口配置
- 2.3 连接到 Redis 服务器
- 三 . 通用命令
- 3.1 set 和 get
- 3.2 exists 和 del
- 3.3 keys
- 3.4 expire、ttl、type
- 三 . string 相关命令
- 3.1 mset / mget
- 3.2 getrange / setrange
- 3.3 append
- 3.4 incr / decr
- 3.5 mset、mget
- 3.6 append、incr、decr
- 四 . list 类型
- 4.1 lpush、lrange、rpush
- 4.2 lpop、rpop
- 4.3 blpop 和 brpop
- 4.4 llen
- 五 . set 类型
- 5.1 sadd、smembers
- 5.2 sismember
- 5.3 scard
- 5.4 spop
- 5.5 sinter、sinterstore
- 六 . hash 类型
- 6.1 hset、hget
- 6.2 hexists
- 6.3 hdel
- 6.4 hkeys、hvals
- 6.5 hmset、hmget
- 七 . zset 类型
- 7.1 zadd、zrange
- 7.2 zcard
- 7.3 zrem
- 7.4 zscore
- 7.5 zrank
Hello , 大家好 , 这个专栏给大家带来的是 Redis 系列 !
我们之前主要学习的是各种 Redis 的基本操作所对应的命令 , 都是在 Redis 的客户端的命令行中手动执行的 , 但是这种方式并不是日常开发主要的形式 .
在日常工作中 , 最常见的就是用程序来操作 Redis , 利用 Redis 提供的 API 来实现一些功能 .本专栏旨在为初学者提供一个全面的 Redis 学习路径,从基础概念到实际应用,帮助读者快速掌握 Redis 的使用和管理技巧。通过本专栏的学习,能够构建坚实的 Redis 知识基础,并能够在实际学习以及工作中灵活运用 Redis 解决问题 .
专栏地址 : Redis 入门实践
一 . 认识 RESP
那为什么我们通过代码就可以编写出一个自定义的 Redis 客户端呢 ?
我们先来回顾一个知识 , 在网络通信过程中 , 会用到很多的协议 , 从下往上的顺序依次是 :
- 物理层
- 数据链路层 : 以太网协议
- 网络层 : IP 协议
- 传输层 : TCP/UDP 协议
- 应用层 : 自定义协议 (比如 : HTTP 协议)
虽然业界有许多成熟的自定义协议 , 但是更多的时候 , 大家都会选择自定义应用层协议 , Redis 应用层的协议就是自定义的协议 .
那客户端按照应用层协议发送请求 , 服务器按照协议内容进行解析 , 再按照这个协议去构造响应 , 客户端去解析响应 . 那我们要想通信能够完成 , 就需要开发客户端和开发服务器的程序员都非常清楚协议的细节 .
那如果我们想要开发一个 Redis 客户端 , 也需要知道 Redis 的应用层协议 , 我们也可以从官网中获取到 Redis 的应用层协议 : https://redis.io/docs/reference/protocol-spec
那 RESP 就是 Redis 的自定义的应用层协议的名字
我们来阅读以下这篇文档
简单好实现 : Redis 的客户端使用一种叫做 RESP 的协议来去跟 Redis 服务器进行通讯 .
可以快速进行解析 : RESP 可以识别不同的类型 , 比如整型、字符串、数组 .
客户端和服务器是基于 TCP 协议进行连接的 , 但是其实跟 TCP 关系没多大 , 只是借助 TCP 这个平台
Redis 客户端请求和响应是一问一答类型的
客户端给服务器发送一个请求 , 服务器返回给客户端一个响应
客户端给服务器发送的是 Redis 命令 , 以 bulk strings 数组的形式发送的
那不同的命令返回结果也不同 , 有的命令直接返回 ok , 有的命令可能返回整数 …
如果是简单的字符串 , 用 ‘+’ 表示 , 如果是简单的错误 , 用 ‘-’ 表示 …
下面还介绍了一个样例 , 服务端返回 OK 时候的表示
那服务器返回 OK 就会返回这串字符串 , 将这串字符串写入到 TCP 的 socket 中
因此 , Redis 的客户端和服务器要做的工作 , 就是
- 按照上述格式构造出字符串 , 写入 socket 中
- 从 socket 中读取字符串 , 按照上述格式进行解析
那我们介绍 RESP 只是希望大家了解一下 Redis 底层是怎样通信的 , 并不影响后续代码的编写
二 . 前置操作
Redis 在官网上公开了自定义的应用层协议 : RESP , 那任何一个第三方都可以根据约定好的协议就可以实现出一个和 Redis 服务器通信的客户端程序 .
那也有很多大佬已经实现好了现成的客户端程序 , 我们可以直接调用 , 就不必再关心里面的细节了 .
在 Java 中 , 比较常用的是 Jedis , 因为他所提供的 API 和 Redis 的命令非常相似 , 十分好上手 .
那我们创建一个 Maven 项目 , 来去演示一系列的操作
2.1 创建项目
打开我们的 IDEA
然后在 pom.xml 中引入 Jedis 的依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.3</version>
</dependency>
然后我们就可以新建一个类 , 来去模拟 Jedis 的操作了
2.2 关于开放 Redis 端口的问题
我们开发代码 , 一般都使用 Windows 系统 , 但是我们的 Redis 是存在云服务器上的 , 要是使用 127.0.0.1 访问到云服务器上面的 Redis 肯定是实现不了的
❓ 那我们修改成云服务器的外网 IP 再去访问行不 ?
也是不可以的 , 我们 Redis 的默认端口 6379 默认是被云服务器的防火墙给保护起来的 .
❓ 那我们再把 6379 给放开不就好了 ?
不可以 ! 千万不要这样做 ! Redis 是非常容易被黑客攻击的 , Redis 的端口一旦公开到网上 , 就特别容易被入侵 !
虽然我们之前开放过 tomcat 的端口 , 这是因为 tomcat 端口的安全性非常高 . 但是 Redis 的 6379 端口 , 安全性非常差 , 一旦你开了 , 不出 3 天 , 服务器就要死翘翘 .
那我给 Redis 换个端口 , 是不是就安全了 ? -> 掩耳盗铃 , 还是不安全的 .
那我们有两种方案解决 :
- 直接让 Java 程序也在 Linux 上面运行 [不推荐]
需要我们把代码编写完毕之后 , 打成一个 jar 包 , 然后把 jar 包拷贝到云服务器上去执行
比较麻烦
- 配置 SSH 端口转发 , 把云服务器的 Redis 端口 , 映射到本地主机 [推荐]
2.2.1 端口转发?
我们的 Windows 主机和云服务器是通过 SSH 连接起来的
那一个 Linux 主机上 , 需要映射的 Windows 设备有很多 , SSH 也有可能需要来给多个端口传递数据 , 这个时候 , 为了区分不同的端口 , 往往会把服务器的端口在本地用另外一个端口来表示
这样就实现了本地和云服务器端口的对应
只要咱们进行简单的配置 , 后续就把服务器的端口当成一个本地端口来使用即可
2.2.2 端口配置
打开我们的 XShell
SSH 端口转发 = SSH = SSH 隧道
只有当 SSH 连接上了之后 , 端口转发才生效
那把 SSH 连接断开 , 端口转发自然就失效了
那我们现在就可以检验一下是否生效了
使用 netstat 命令查看本地 8888 端口是否被绑定
那当我们配置了端口转发之后 ,如果之前配置过了端口转发 , 一定要断开之前的连接 , 重新连接才能生效
那我们后续 , 在 Java 代码中 , 通过 127.0.0.1:8888 就可以操作到我们的云服务器的 Redis 了 , 同时 , 外面的客户端是无法直接访问云服务器的 6379 端口的
我们再介绍一下 XTerminal 的配置方法
2.3 连接到 Redis 服务器
要想连接到 Redis 的服务器 , 我们需要使用 JedisPool 这样的对象 . 在 JedisPool 的构造方法中 , 就需要指定我们需要连接的服务器地址
注意服务器地址应该设置成本机的环回 IP + 我们配置的端口映射
import redis.clients.jedis.JedisPool;
public class RedisDemo {
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
}
}
接下来我们就需要从 JedisPool 这个 Redis 连接池中取出一个连接 , 连接用完之后需要释放
所以我们可以直接选择 try-with-resources 这样的方式自动释放
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemo {
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
}
}
}
那之后我们就可以使用 Redis 的各种命令了
我们以 Redis 中的 ping 命令来测试连接是否成功
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemo {
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
// Redis 的各种命令, 都可以对应到 Jedis 对象的各种方法
// 验证 Redis 的连通性
String pong = jedis.ping();
System.out.println(pong);
}
}
}
注意 : 我们要确保云服务器的 Redis 的配置文件里面的配置是正确的
输入 cd /etc/redis/ , 然后用 vim 打开 redis.conf
判断这两个位置是否跟我的一致 , 不一致的话就要修改一下
控制台打印 PONG 代表连接成功
三 . 通用命令
3.1 set 和 get
我们先来模拟一下最基本的 get 和 set 的使用
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemo {
/**
* 模拟 get 和 set 的使用
*/
public static void test01(Jedis jedis) {
System.out.println("模拟 get 和 set 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 模拟 set 的使用
jedis.set("k1", "v1");
jedis.set("k2", "v2");
// 模拟 get 的使用
String v1 = jedis.get("k1");
String v2 = jedis.get("k2");
System.out.println("value1 = " + v1);
System.out.println("value2 = " + v2);
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
}
那 set 命令还有一些其他版本
我们可以看到 , set 方法还可以有第三个参数
那我们就可以先创建一个 SetParams 对象 , 然后调用 ex / nx / xx 等方法
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
public class RedisDemo {
/**
* 模拟 get 和 set 的使用
*/
public static void test01(Jedis jedis) {
System.out.println("模拟 get 和 set 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 模拟 set 的使用
jedis.set("k1", "v1");
jedis.set("k2", "v2");
// 模拟 get 的使用
String v1 = jedis.get("k1");
String v2 = jedis.get("k2");
System.out.println("value1 = " + v1);
System.out.println("value2 = " + v2);
// set 的其它参数
SetParams params = new SetParams();
params.ex(10);// 设置超时时间为 10s
params.xx();// 存在才去修改(更新)
// params.nx();// 不存在才去创建
jedis.set("k1", "v3", params);// 此时 k1 存在, 可以被修改
System.out.println(jedis.get("k1"));
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
}
我们可以看一下运行结果
3.2 exists 和 del
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
public class RedisDemo {
/**
* 模拟 exists 和 del 的使用
*/
public static void test02(Jedis jedis) {
System.out.println("模拟 exists 和 del 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("k1", "111");
jedis.set("k2", "222");
// 判断对应的 key 是否存在
boolean result = jedis.exists("k1");
System.out.println("k1 是否存在 : " + result);// true
// 删除对应键值对
// del 方法返回值为 long, 代表删除成功的个数
long result2 = jedis.del("k2");
System.out.println("删除成功的个数 : " + result2);// 1
// 再去判断 k2 是否存在
boolean result3 = jedis.exists("k2");
System.out.println("k2 是否存在 : " + result3);// false
// 可以删除多个 key
// 但是仍然只会返回删除成功的个数
long result4 = jedis.del("k1", "k2", "k3");
System.out.println("删除成功的个数 : " + result4);// 1
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
}
3.3 keys
我们之前学习 keys 命令的时候 , 他有很多 pattern .
那我们先来看一下最基本的情况 : keys * , 查询所有的 key
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
import java.util.Set;
public class RedisDemo {
/**
* 模拟 keys 的使用
*/
public static void test03(Jedis jedis) {
System.out.println("模拟 keys 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("k1", "111");
jedis.set("k2", "222");
jedis.set("k3", "333");
jedis.set("k4", "444");
// 模拟 keys 的使用
// 返回值是 Set 类型
Set<String> keys = jedis.keys("*");// 相当于 keys *
System.out.println(keys);
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
}
运行结果 :
我们需要知道的是 , keys 命令的返回值是 Set 类型
之所以使用 Set 类型而不是 List 类型的原因是 : Redis 中要求 key 是不能重复的 , 并且对于 key 的先后顺序也并没有要求 , 所以使用 Set 类型会更合适一些
3.4 expire、ttl、type
我们先来看 ttl 和 expire 的使用方法
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
import java.util.Set;
public class RedisDemo {
/**
* 模拟 expire、ttl 的使用
*/
public static void test04(Jedis jedis) {
System.out.println("模拟 expire、ttl、type 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("k1", "111");
// 设置过期时间
jedis.expire("k1", 10);// 设置过期时间为 10s
// 获取剩余时间
// ttl 返回值为 long
long time = jedis.ttl("k1");
System.out.println("当前键值对剩余时间为 " + time);
// 等待 3s
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 休眠 3s 之后继续获取剩余时间
time = jedis.ttl("k1");
System.out.println("当前键值对剩余时间为 " + time);
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
}
我们可以看一下运行结果
这就代表我们 expire 设置生效了 , 并且休眠 3s 之后还能正确获取剩余时
那接下来我们再来看 type 命令
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
import java.util.Set;
public class RedisDemo {
/**
* 模拟 type 的使用
*/
public static void test05(Jedis jedis) {
System.out.println("模拟 type 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("k1", "111");// 设置成字符串类型
String type1 = jedis.type("k1");
System.out.println("当前数据的类型为: " + type1);
jedis.lpush("k2","111","222","333");
String type2 = jedis.type("k2");
System.out.println("当前数据的类型为: " + type2);
jedis.hset("k3","f1","111");
String type3 = jedis.type("k3");
System.out.println("当前数据的类型为: " + type3);
jedis.sadd("k4","111","222","333");
String type4 = jedis.type("k4");
System.out.println("当前数据的类型为: " + type4);
jedis.zadd("k5",10,"zhangsan");
String type5 = jedis.type("k5");
System.out.println("当前数据的类型为: " + type5);
}
public static void main(String[] args) {
// 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 从 Redis 连接池中取出一个连接
try (Jedis jedis = jedisPool.getResource()) {
test05(jedis);
}
}
}
我们可以看一下运行结果
三 . string 相关命令
我们给大家介绍这几个命令 :
- 针对多个 key 进行操作 : mset / mget
- 获取 / 设置字符串指定范围内容 : getrange / setrange
- 拼接字符串 : append
- 对数据进行自增自减 : incr / decr
3.1 mset / mget
注意 : mget 的返回值是 List , 而不是 Set
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class RedisDemoString {
// mget mset 的用法
public static void test1(Jedis jedis) {
// 1. 清空数据库
// 避免上一组的测试数据影响到下一组的测试结果
jedis.flushDB();
// 2. 设置多个键值对
jedis.mset("key1", "value1", "key2", "value2", "key3", "value3");
// 3. 获取多个键值对
// 返回值: List
List<String> values = jedis.mget("key1", "key2", "key3");
System.out.println("values : " + values);
}
public static void main(String[] args) {
// 1. 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 2. 创建 Jedis 对象
try (Jedis jedis = jedisPool.getResource()) {
test1(jedis);
}
}
}
那我们的 value 与上面设置的 set 的顺序是一一对应的
那假如我们中间获取一个不存在的 key , 会发生什么 ?
如果获取不存在的值 , 就会打印 null , 这也说明了有几个参数 , 就有几个返回结果
3.2 getrange / setrange
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class RedisDemoString {
// getrange / setrange 的使用
public static void test2(Jedis jedis) {
// 1. 清空数据库
// 避免上一组的测试数据影响到下一组的测试结果
jedis.flushDB();
// 2. 添加数据
jedis.set("key", "HelloWorld!");
// 3. 获取指定区间的顺序
// 左闭右闭区间
String result = jedis.getrange("key", 2, 5);
System.out.println("result = " + result);
// 4. 设置指定区间的值
jedis.setrange("key", 2, "666");
System.out.println("修改之后的值: " + jedis.get("key"));
}
public static void main(String[] args) {
// 1. 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 2. 创建 Jedis 对象
try (Jedis jedis = jedisPool.getResource()) {
test2(jedis);
}
}
}
3.3 append
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class RedisDemoString {
// append 的使用
public static void test3(Jedis jedis) {
// 1. 清空数据库
// 避免上一组的测试数据影响到下一组的测试结果
jedis.flushDB();
// 2. 模拟数据
jedis.set("key", "Hello");
// 3. 追加数据
jedis.append("key", "World");
// 4. 查看追加后的数据
System.out.println("修改之后的值 : " + jedis.get("key"));
}
public static void main(String[] args) {
// 1. 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 2. 创建 Jedis 对象
try (Jedis jedis = jedisPool.getResource()) {
test3(jedis);
}
}
}
3.4 incr / decr
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class RedisDemoString {
// incr / decr 的使用
public static void test4(Jedis jedis) {
// 1. 清空数据库
// 避免上一组的测试数据影响到下一组的测试结果
jedis.flushDB();
// 2. 模拟数据
// 这次要模拟一个整数的数据
jedis.set("key", "100");
// 3. 自增操作
// 返回自增之后的值
long result1 = jedis.incr("key");
System.out.println("自增操作返回的值: " + result1);// 预期是 101
// 4. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 101
// 5. 自减操作
long result2 = jedis.decr("key");
System.out.println("自减操作返回的值: " + result2);// 预期是 100
// 6. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 100
}
public static void main(String[] args) {
// 1. 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 2. 创建 Jedis 对象
try (Jedis jedis = jedisPool.getResource()) {
test4(jedis);
}
}
}
那 incr 和 decr 还可以指定增加或者删除的值 , 使用 incrby 和 decrby
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class RedisDemoString {
// incr / decr 的使用
public static void test4(Jedis jedis) {
// 1. 清空数据库
// 避免上一组的测试数据影响到下一组的测试结果
jedis.flushDB();
// 2. 模拟数据
// 这次要模拟一个整数的数据
jedis.set("key", "100");
// 3. 自增操作
// 返回自增之后的值
long result1 = jedis.incr("key");
System.out.println("自增操作返回的值: " + result1);// 预期是 101
// 4. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 101
// 5. 自减操作
long result2 = jedis.decr("key");
System.out.println("自减操作返回的值: " + result2);// 预期是 100
// 6. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 100
// 7. 指定增加的值
long result3 = jedis.incrBy("key", 10);
System.out.println("指定增加的值最后变成了: " + result3);// 预期是 110
// 8. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 110
// 9. 指定减少的值
long result4 = jedis.decrBy("key", 5);
System.out.println("指定减少的值最后变成了: " + result4);// 预期是 105
// 10. 获取 key 的值
System.out.println("此时 key 的值为: " + jedis.get("key"));// 预期是 105
}
public static void main(String[] args) {
// 1. 连接到 Redis 服务器上
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
// 2. 创建 Jedis 对象
try (Jedis jedis = jedisPool.getResource()) {
test4(jedis);
}
}
}
3.5 mset、mget
我们先来看 mset 和 mget 这一组
mset 可以设置多组键值对 , mget 可以获取多组键值对
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class StringDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 mset mget 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 模拟 mset 设置多组数据
jedis.mset("k1","v1","k2","v2","k3","v3");
// 模拟 mget 获取多组数据
List<String> values1 = jedis.mget("k1","k2","k3");
System.out.println("value 的值为 : " + values1);
}
}
那我们来看一下运行结果
那要注意的是 , mget 的返回值是 List 而不是 Set
之前学习 keys 命令的时候 , 他的返回值是 Set , 是因为 key 要求不能重复 . 而我们的 value 是可以重复的 , 所以使用 List 来去接收
那如果我们获取的多个键值对中某个 key 不存在 , 该怎样返回呢 ?
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class StringDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 mset mget 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 模拟 mset 设置多组数据
jedis.mset("k1","v1","k2","v2","k3","v3");
// 模拟 mget 获取多组数据
List<String> values1 = jedis.mget("k1","k2","k3");
System.out.println("value 的值为 : " + values1);
// 如果某个 key 在 Redis 中不存在
// 则对应的位置用 null 表示
List<String> values2 = jedis.mget("k1","k2","k100","k3");
System.out.println("value 的值为 : " + values2);
}
}
我们可以通过运行结果来看一下
那我们就知道了 , 如果某个 key 在 Redis 上不存在 , 则对应的 value 用 null 来表示
那我们再来看一下 getrange 和 setrange
getrange 的作用是获取到 [start , end] 区间内的数据
setrange 的作用是从 start 位置开始 , 修改内容为指定的字符串
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class StringDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
private static void test02(Jedis jedis) {
System.out.println("模拟 getrange 和 setrange 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造测试数据
jedis.set("key","abcdefghigklmn");
// 获取 [start,end] 区间的数据
String str1 = jedis.getrange("key",2,5);
System.out.println(str1);
// 从 start 位置开始, 修改内容为指定的字符串
// 从下标为 2 的位置开始修改, 修改成 hahaha
jedis.setrange("key",2,"hahaha");
String str2 = jedis.get("key");
System.out.println(str2);
}
}
我们可以来看一下运行结果
3.6 append、incr、decr
append 的作用是拼接字符串
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class StringDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
private static void test03(Jedis jedis) {
System.out.println("模拟 append 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("key", "Hello");
// 拼接字符串
jedis.append("key", "World");
String value = jedis.get("key");
System.out.println("value = " + value);
}
}
我们可以看一下运行结果
我们再来看一下 incr 和 decr 的用法
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class StringDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 incr 和 decr 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造数据
jedis.set("key", "100");
// 模拟 incr 的使用
// incr 返回值类型为 long, 代表自增后的结果
long result1 = jedis.incr("key");
System.out.println("自增之后的值为 : " + result1);
String value1 = jedis.get("key");
System.out.println("value 的值为 : " + value1);
// 模拟 decr 的使用
// decr 返回值类型为 long, 代表自减后的结果
long result2 = jedis.decr("key");
System.out.println("自增之后的值为 : " + result2);
String value2 = jedis.get("key");
System.out.println("value 的值为 : " + value2);
}
}
还有其他的比如 incrby、incrbyfloat 命令 , 我们就不进行演示了
四 . list 类型
4.1 lpush、lrange、rpush
lpush 的作用是向列表中添加元素 (头插法)
lrange 的作用是可以获取到列表中的元素
rpush 就相当于尾插法
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 lpush 和 lrange 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 头插法向列表中插入元素
// 返回值为插入成功之后 list 的长度
jedis.lpush("key", "111", "222", "333");
// 获取列表中的元素
// 返回值为 List
List<String> result1 = jedis.lrange("key", 0, -1);
System.out.println("头插法之后的列表为 : " + result1);
// 尾插法向列表中插入元素
jedis.rpush("key", "555", "666");
List<String> result2 = jedis.lrange("key", 0, -1);
System.out.println("尾插法之后的列表为 : " + result2);
}
}
我们可以看一下运行结果
4.2 lpop、rpop
lpop 就相当头头删法
rpop 就相当于尾删法
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
private static void test02(Jedis jedis) {
System.out.println("模拟 lpush 和 lrange 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造列表中的数据
jedis.rpush("key", "111", "222", "333", "444");
// 从列表尾部删除元素
String result1 = jedis.rpop("key");
System.out.println("尾删法删除的值为 : " + result1);
result1 = jedis.rpop("key");
System.out.println("尾删法删除的值为 : " + result1);
// 从列表头部删除元素
String result2 = jedis.lpop("key");
System.out.println("头删法删除的值为 : " + result2);
result2 = jedis.lpop("key");
System.out.println("头删法删除的值为 : " + result2);
// 此时列表为空
// 继续获取就会获取到 null
result1 = jedis.rpop("key");
System.out.println("尾删法删除的值为 : " + result1);
result2 = jedis.lpop("key");
System.out.println("头删法删除的值为 : " + result2);
}
}
4.3 blpop 和 brpop
blpop 和 brpop 就相当于阻塞版本的 lpop 和 rpop
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
private static void test03(Jedis jedis) {
System.out.println("模拟 blpop 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 我们先在列表为空的时候去执行以下 blpop
// 第一个参数: 超时时间(单位: s)
// 第二个参数: 要获取的 key
// 返回值是一个二元组, 使用 List 接收
// 一个是从哪个 key 获取到的结果, 一个是删除的元素是什么
List<String> result = jedis.blpop(3, "key");
System.out.println("从 " + result.get(0) + " 中获取到的结果");
System.out.println("删除的元素为 : " + result.get(1));
}
}
此时由于我们的 Redis 中并没有数据 , 所以 blpop 就会发生阻塞等待 , 超过设置的时间就会返回 null 导致代码出现空指针异常
那我们可以模拟一下其他客户端插入元素的情况
4.4 llen
llen 的作用是获取到列表的元素个数
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 llen 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造列表中的数据
jedis.rpush("key", "111", "222", "333", "444");
// 获取列表中的元素个数
long len = jedis.llen("key");
System.out.println("列表中的元素个数为 " + len);
}
}
五 . set 类型
5.1 sadd、smembers
sadd 的作用是向集合中添加元素
smembers 是获取到集合中的元素
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 sadd、smembers 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向集合中添加元素
jedis.sadd("key", "111", "222", "333", "444");
// 获取集合中的元素
// smembers 返回值是一个 Set
// 注意: smembers 顺序是无序的, 与插入顺序无关
Set<String> result = jedis.smembers("key");
System.out.println("集合中的元素为 : " + result);
}
}
5.2 sismember
sismember 的作用是判断元素是否在集合中存在
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
private static void test02(Jedis jedis) {
System.out.println("模拟 sismember 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向集合中添加元素
jedis.sadd("key", "111", "222", "333", "444");
// 判断元素是否存在
// sismember 返回值为布尔类型
boolean result1 = jedis.sismember("key", "111");
System.out.println(result1);
// key 不存在就会返回 false
boolean result2 = jedis.sismember("key100", "111");
System.out.println(result2);
// value 不存在也会返回 false
boolean result3 = jedis.sismember("key", "666");
System.out.println(result3);
}
}
5.3 scard
scard 是用来获取集合中的元素个数
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
private static void test03(Jedis jedis) {
System.out.println("模拟 scard 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向集合中添加元素
jedis.sadd("key", "111", "222", "333", "444");
// 获取集合中的元素个数
long len = jedis.scard("key");
System.out.println("集合中的元素个数为 : " + len);
}
}
5.4 spop
spop 的作用是随机删除一个元素
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 spop 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向集合中添加元素
jedis.sadd("key", "111", "222", "333", "444");
// spop 的作用是随机删除一个元素
// 返回值是被删除的元素
String result = jedis.spop("key");
System.out.println("随机删除的值为 : " + result);
}
}
我们可以多次运行来看一下删除的值是否是固定的
5.5 sinter、sinterstore
sinter 和 sinterstore 的作用是用来求多个集合的交集
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test05(jedis);
}
}
private static void test05(Jedis jedis) {
System.out.println("模拟 sinter、sinterstore 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向集合中添加元素
jedis.sadd("key1", "111", "222", "333");
jedis.sadd("key2", "111", "222", "444");
// 求多个集合的交集
Set<String> result1 = jedis.sinter("key1", "key2");
System.out.println("sinter 交集的结果为 : " + result1);
// 将交集的结果保存到另外的 key 中
// sinterstore 的返回值表示交集的个数
long len = jedis.sinterstore("dest", "key1", "key2");
System.out.println("sinterstore 交集的长度为 : " + len);
Set<String> result2 = jedis.smembers("dest");
System.out.println("sinterstore 交集的结果为 : " + result2);
}
}
六 . hash 类型
6.1 hset、hget
hset 的作用是向哈希中添加元素
hget 是用来获取哈希中的元素的
我们先来看一下 hset
他有两种版本 , 一种是正常添加 key-field-value , 另一种是将多组 field-value 打包成一个 Map 进行插入
我们分别来演示
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.Map;
public class HashDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 hset 和 hget 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向哈希中添加一组元素
jedis.hset("k1", "f1", "111");
// 向哈希中添加多组元素
// 将多组 field-value 打包成一个 Map
Map<String, String> fields = new HashMap<>();
fields.put("f2", "222");
fields.put("f3", "333");
jedis.hset("k1", fields);
// 获取哈希中的元素
String result1 = jedis.hget("k1", "f1");
System.out.println("哈希中的元素 : " + result1);
// 如果 key 不存在, 就会获取失败
String result2 = jedis.hget("k100", "f1");
System.out.println("哈希中的元素 : " + result2);
// 如果 field 不存在, 就会获取失败
String result3 = jedis.hget("k1", "f100");
System.out.println("哈希中的元素 : " + result3);
}
}
6.2 hexists
hexists 的作用是用来判断元素是否存在
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.Map;
public class HashDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
private static void test02(Jedis jedis) {
System.out.println("模拟 hexists 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向哈希中添加多组元素
// 将多组 field-value 打包成一个 Map
Map<String, String> fields = new HashMap<>();
fields.put("f1", "111");
fields.put("f2", "222");
fields.put("f3", "333");
jedis.hset("k1", fields);
// 判断某个元素是否存在
// 返回值是布尔类型
boolean result1 = jedis.hexists("k1", "f1");
System.out.println("该元素是否存在 : " + result1);
// 如果 key 不存在, 就会返回 false
boolean result2 = jedis.hexists("k100", "f1");
System.out.println("该元素是否存在 : " + result2);
// 如果 field 不存在, 就会返回 false
boolean result3 = jedis.hexists("k1", "f100");
System.out.println("该元素是否存在 : " + result3);
}
}
6.3 hdel
hedel 的作用是删除指定的 field
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.Map;
public class HashDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
private static void test03(Jedis jedis) {
System.out.println("模拟 hdel 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向哈希中添加多组元素
// 将多组 field-value 打包成一个 Map
Map<String, String> fields = new HashMap<>();
fields.put("f1", "111");
fields.put("f2", "222");
fields.put("f3", "333");
jedis.hset("k1", fields);
// hdel 的作用是删除指定的 key 下面的 field
// 返回值代表删除成功的个数
long delNum = jedis.hdel("k1", "f1", "f2", "f100");
System.out.println("删除成功的个数为 : " + delNum);
// 此时再去判断 f1 和 f2 是否还存在
boolean result1 = jedis.hexists("k1", "f1");
System.out.println("f1 是否存在 : " + result1);
boolean result2 = jedis.hexists("k1", "f2");
System.out.println("f2 是否存在 : " + result2);
}
}
6.4 hkeys、hvals
hkeys 是用来获取哈希中所有的 key
hvals 是用来获取海中所有的 val
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HashDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 hkeys、hvals 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向哈希中添加多组元素
// 将多组 field-value 打包成一个 Map
Map<String, String> fields = new HashMap<>();
fields.put("f1", "111");
fields.put("f2", "222");
fields.put("f3", "333");
jedis.hset("k1", fields);
// hkeys 用来获取所有的 field
// 返回值是 Set 类型
Set<String> result1 = jedis.hkeys("k1");
System.out.println("keys : " + result1);
// hvals 用来获取所有的 value
// 返回值是 List 类型
List<String> result2 = jedis.hvals("k1");
System.out.println("vals : " + result2);
}
}
那要注意的是 , hkeys 的返回值类型为 Set , hvals 的返回值类型为 List
这是因为哈希中要求 key 不能重复 , 所以使用 Set 来去接收 ; 而 value 是可以重复的 , 所以使用 List 来去接收
6.5 hmset、hmget
hmset 的作用与 hset 差不多 , 都是用来添加哈希的 , 并且添加多组哈希都需要用到 Map 辅助
hmget 的作用是获取多组哈希的值
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HashDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test05(jedis);
}
}
private static void test05(Jedis jedis) {
System.out.println("模拟 hmset、hmget 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// hmset 可以添加多组哈希
// 但仍然需要将多组 field-value 打包成一个 Map
Map<String, String> map = new HashMap<>();
map.put("f1", "111");
map.put("f2", "222");
map.put("f3", "333");
jedis.hmset("k1", map);
// hmget 可以获取多组哈希
List<String> values = jedis.hmget("k1", "f1", "f2", "f3", "f4");
System.out.println("values : " + values);
}
}
那他的特点就是会根据 field 的顺序来去打印 value 的顺序 , 也就是说 field-value 是严格对应的
hkeys 和 hvals 则不是 , 他们都是随机打印的 , 并不能一一对应
七 . zset 类型
7.1 zadd、zrange
zadd 是向有序集合中添加元素
zrange 是用来获取有序集合的所有元素
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 zadd、zrange 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向 zset 中添加一组元素
jedis.zadd("key", 10.0, "zhangsan");
// 也可以向 zset 中添加多组元素
// 但是也需要借助 Map 来去设置 score 和 value
Map<String, Double> map = new HashMap<>();
map.put("lisi", 20.0);
map.put("wangwu", 30.0);
jedis.zadd("key", map);
// 获取 zset 中的元素
// 返回值类型为 List
List<String> members = jedis.zrange("key", 0, -1);
System.out.println("有序集合中的元素为 : " + members);
}
}
如果我们想既获取到 members , 又获取到 scores , 那就需要使用 zrangewithscores 这个方法了
但是 zrangewithscores 的返回值类型有些特殊 , 需要我们留意一下
那这个 Tuple 是 Jedis 提供给我们的数据类型 , 代表元组 (也就是一组数据)
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test01(jedis);
}
}
private static void test01(Jedis jedis) {
System.out.println("模拟 zadd、zrange 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 向 zset 中添加一组元素
jedis.zadd("key", 10.0, "zhangsan");
// 也可以向 zset 中添加多组元素
// 但是也需要借助 Map 来去设置 score 和 value
Map<String, Double> map = new HashMap<>();
map.put("lisi", 20.0);
map.put("wangwu", 30.0);
jedis.zadd("key", map);
// 获取 zset 中的元素
List<String> members = jedis.zrange("key", 0, -1);
System.out.println("有序集合中的元素为 : " + members);
// 既获取 members, 又获取 scores
List<Tuple> memberswithscores = jedis.zrangeWithScores("key", 0, -1);
System.out.println("有序集合中的元素为 : " + memberswithscores);
// 获取其中某一个元素
String member = memberswithscores.get(0).getElement();
double score = memberswithscores.get(0).getScore();
System.out.println("第一个元素 : " + member + " , 他的成绩为 : " + score);
}
}
7.2 zcard
zcard 是用来统计有序集合的元素个数的
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test02(jedis);
}
}
private static void test02(Jedis jedis) {
System.out.println("模拟 zcard 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造多组有序集合数据
jedis.zadd("key", 10, "zhangsan");
jedis.zadd("key", 20, "lisi");
jedis.zadd("key", 30, "wangwu");
// 获取有序集合的元素个数
long len = jedis.zcard("key");
System.out.println("有序集合的元素个数为 : " + len);
}
}
7.3 zrem
zrem 用来删除指定元素
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test03(jedis);
}
}
private static void test03(Jedis jedis) {
System.out.println("模拟 zrem 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造多组有序集合数据
jedis.zadd("key", 10, "zhangsan");
jedis.zadd("key", 20, "lisi");
jedis.zadd("key", 30, "wangwu");
// 删除指定元素
// 可以删除多组数据, 返回值代表删除成功的个数
long remNum = jedis.zrem("key", "zhangsan", "lisi");
System.out.println("删除成功的元素个数 : " + remNum);
// 获取剩余元素
List<Tuple> result = jedis.zrangeWithScores("key", 0, -1);
System.out.println("剩余元素 : " + result);
}
}
7.4 zscore
zscore 的作用是根据 member 来去找到对应的 score
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 zscore 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造多组有序集合数据
jedis.zadd("key", 10, "zhangsan");
jedis.zadd("key", 20, "lisi");
jedis.zadd("key", 30, "wangwu");
// 根据 member 获取对应的分数
double score1 = jedis.zscore("key", "zhangsan");
System.out.println("score = " + score1);
}
}
但是有一个需要注意的位置 : 就是我们在接收 score 的时候 , 使用的是 double 来去接收的
如果 member 存在 , 那么正常返回成绩 , 没什么问题 ; 但是如果 member 不存在呢 ?
member 不存在 , zscore 就会返回 null , 用 double 去接收 null 是会触发空指针异常的 .
所以我们尽量谁用包装类来去接收
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test04(jedis);
}
}
private static void test04(Jedis jedis) {
System.out.println("模拟 zscore 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造多组有序集合数据
jedis.zadd("key", 10, "zhangsan");
jedis.zadd("key", 20, "lisi");
jedis.zadd("key", 30, "wangwu");
// 根据 member 获取对应的分数
// 注意: 请使用包装类进行接收, 避免触发空指针异常
Double score1 = jedis.zscore("key", "zhangsan");
System.out.println("score = " + score1);
}
}
7.5 zrank
zrank 的作用是获取到某个 member 他所对应的排名 (下标)
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.resps.Tuple;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZSetDemo {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
test05(jedis);
}
}
private static void test05(Jedis jedis) {
System.out.println("模拟 zrank 的使用");
// 避免上一组测试的残留数据影响到本组测试结果
// 所以需要先清空一下数据库
jedis.flushDB();
// 构造多组有序集合数据
jedis.zadd("key", 10, "zhangsan");
jedis.zadd("key", 20, "lisi");
jedis.zadd("key", 30, "wangwu");
// 获取某个 member 的排名
// 注意: 返回值用 Long 包装类接收, 避免空指针异常
Long rank = jedis.zrank("key", "lisi");
System.out.println("rank : " + rank);
}
}
这篇文章知识含量超级大 , 如果对大家有帮助的话 , 还请一键三连~