在介绍完Redis服务器的原理与内部结构之后,接下来我们将介绍如何在程序中高效使用Redis服务器。与关系型数据库编程类似,应用程序是作为客户端与Redis服务器通信的。
Redis客户端与服务器端的通信协议是独立于编程语言的。换句话说,使用任何语言都能实现Redis的客户端。因此,对于每一种流行的编程语言,Redis都有相应的客户端。我们在下面列举几个Redis开发人员推荐使用的客户端。本文将重点介绍Java客户端的使用方法。我们将在下一章介绍Python客户端的使用方法。
编程语言 | 客户端库 |
---|---|
C | hiredis, hiredis-vip |
Go | Radix, Redigo |
Java | Jedis, Lettuce, Redisson |
Python | redis-py, walrus |
Scala | scala-redis |
可点击查看更多支持的编程语言和客户端。
如果读者运行的是Ubuntu Linux服务器的话,可以使用如下命令安装Redis服务器。如下示例使用的是Ubuntu 20.04 LTS版本。Ubuntu服务器可以在这里免费下载。
> sudo apt-get update
> sudo apt-get install redis-server
安装完毕后,我们可以使用如下命令启动Redis服务器,并测试Redis服务器是否安装成功。如果能够成功发送ping命令,并收到响应PONG,则说明Redis系统安装成功。
> redis-server
> redis-server --version
Redis server v=5.0.7 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=636cde3b5c7a3923
> redis-cli
redis 127.0.0.1:6379> ping
PONG
如果读者使用Maven维护Java工程的话,可以在pom.xml文件中添加如下依赖包。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
Jedis的用法很简单,客户端需要首先创建一个redis.clients.jedis.Jedis类的对象,然后再使用该对象操作Redis数据库。
在创建Redis对象时,如果是连接本机运行的Redis服务器的,并且使用默认接口的话,可以直接使用默认构造函数Jedis()。如果连接的是远程数据库,或者该数据库未使用默认接口的话,可使用Jedis(String host, int port)构造函数创建对象。
在获得了Redis对象实例之后,就可以使用set()/get()成员方法设置和查询数据了。如下面的示例代码所示,该程序连接了本机的Redis服务器,并向其设置了name/value对。最后,程序向Redis服务器查询name对应的值。
import redis.clients.jedis.Jedis;
public class JedisClient {
public static void main(String[] args) {
// 连接本地的Redis服务器
String host = "localhost";
int port = 6379;
Jedis jedis = new Jedis(host, port);
// 向Redis数据库创建name/value的字符串对
jedis.set("name", "value");
// 向Redis服务器查询字符串name对应的value值
String value = jedis.get("name");
}
}
从上面的代码可以看出,Jedis对象通过get()/set()方法查询和设置字符串对。我们在下面的代码中展示链表、集合、哈希、有序集合的使用方法。它们都有对应的成员方法支持数据创建、查询和删除。读者应该能从成员方法的名称推测出它们的功能,因为它们与相应的Redis命令的名称相同。
import java.util.Set;
import java.util.Map;
import redis.clients.jedis.Jedis;
public class JedisClient {
public static void main(String[] args) {
// 连接本地的Redis服务器
Jedis jedis = new Jedis();
// 链表操作示例
jedis.rpush("listname", "firstElement"); // 从链表尾部添加元素firstElement
jedis.rpush("listname", "secondElement"); // 从链表尾部添加元素secondElement
String lastElement = jedis.rpop("listname"); // 从链表尾部移除一个元素
System.out.println(lastElement); // 打印secondElement
// 集合操作示例
jedis.sadd("primeNumberSet", "2"); // 向质数集合添加数字2
jedis.sadd("primeNumberSet", "3"); // 向质数集合添加数字3
Set<String> primeNumbers = jedis.smembers("primeNumberSet"); // 查询质数集合中所有的元素
boolean exists = jedis.sismember("primeNumberSet", "2"); // 查询数字2是否在质数集合中
// 哈希表操作示例
jedis.hset("dictName", "name1", "value1"); // 向哈希表dictName插入name1/value1对
jedis.hset("dictName", "name2", "value2"); // 向哈希表dictName插入name2/value2对
Map<String, String> allKeyValues = jedis.hgetAll("dictName"); // 查询哈希表dictName中所有的key/value对
String value2 = jedis.hget("dictName", "name2"); // 向哈希表dictName中查询name2对应的value值
// 有序集合示例
jedis.zadd("confidenceOfProgLang", 100.0, "java"); // 向集合添加元素java,分数100.0
jedis.zadd("confidenceOfProgLang", 90.0, "python"); // 向集合添加元素python,分数90.0
Double confidenceInJava = jedis.zscore("confidenceOfProgLang", "java"); // 查询java语言的分数
System.out.println(confidenceInJava);
}
}
和关系型数据库类似,Redis也支持事务处理。使用事务处理功能能为客户端提供:
下面的例子展示了客户端程序在一个事务中创建了两个key/value对。事务对象是由调用multi()方法创建的。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class JedisClient {
public static void main(String[] args) {
Jedis jedis = new Jedis();
Transaction transaction = jedis.multi();
transaction.set("name1", "value1");
transaction.set("name2", "value2");
transaction.exec();
}
}
Pipeline是Redis数据库的一个重要特性。当客户端向服务器发送一条命令之后,客户端并不需要等待命令的应答才能发送下一条命令。多条命令可以一次性下发,然后,再一次性读取它们的结果。Redis服务器会按照收到命令的顺序返回应答。
例如,下面的程序示例中,客户端程序使用Pipeline对象下发了三条命令。前两条命令向链表listname添加两个元素,最后一条命令移除链表中最后一个元素。rpop()方法返回Response类型的对象。在由Response对象获取命令返回值之前,程序需要调用sync()成员方法以等待接收所有命令的执行结果。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
public class JedisClient {
public static void main(String[] args) {
// 连接本地的Redis服务器
Jedis jedis = new Jedis();
// 创建一个Pipeline对象
Pipeline pipeline = jedis.pipelined();
pipeline.rpush("listname", "firstElement"); // 使用Pipeline向链表添加元素firstElement
pipeline.rpush("listname", "secondElement"); // 使用Pipeline向链表添加元素secondElement
Response<String> lastElement = pipeline.rpop("listname"); // 使用Pipeline从链表尾部移除一个元素
pipeline.sync(); // 等待所有命令的结果
System.out.println(lastElement.get()); // 调用get()方法获得结果
}
}
发布者/订阅者模式是由发布者和订阅者两个角色组成的。下面的第一个程序扮演的是订阅者。它通过使用subscribe()成员方法订阅了频道littlewaterdrop_study。subscribe()成员方法接收两个参数。第一个参数是JedisPubSub类型的对象。第二个参数是频道名称。JedisPubSub是一个抽象类。它包含了一些空的成员方法(),以响应不同的事件。其中,onMessage()成员方法就是一个接收新消息的响应函数。每当发布者向频道推送一条新的消息后,订阅者的onMessage()方法就会被调用,新消息的内容会以参数的方式传入进来。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class JedisSubscriber {
public static void main(String[] args) {
// 连接本地的Redis服务器
Jedis jedis = new Jedis();
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// handle message
System.out.println(String.format(
"A message %s is received from channel %s", message, channel
));
}
}, "littlewaterdrop_study");
}
}
发布者的逻辑简单一些,发布者只需要向频道发送消息即可。下面的源代码示例使用publish()成员方法向频道littlewaterdrop_study发送了一条消息"Welcome to Little Waterdrop"。
import redis.clients.jedis.Jedis;
public class JedisPublisher {
public static void main(String[] args) {
// 连接本地的Redis服务器
Jedis jedis = new Jedis();
jedis.publish("littlewaterdrop_study", "Welcome to Little Waterdrop");
}
}
本章首先介绍了Redis客户端支持的流行的编程语言以及函数库。然后,使用了Jedis库作为Java客户端的一个例子,讲述了Redis编程的常用场景。
注册用户登陆后可留言