programming_java

第十三章 Redis编程-Java篇

1 概述

在介绍完Redis服务器的原理与内部结构之后,接下来我们将介绍如何在程序中高效使用Redis服务器。与关系型数据库编程类似,应用程序是作为客户端与Redis服务器通信的。

Redis客户端与服务器端的通信协议是独立于编程语言的。换句话说,使用任何语言都能实现Redis的客户端。因此,对于每一种流行的编程语言,Redis都有相应的客户端。我们在下面列举几个Redis开发人员推荐使用的客户端。本文将重点介绍Java客户端的使用方法。我们将在下一章介绍Python客户端的使用方法。

编程语言客户端库
Chiredis, hiredis-vip
GoRadix, Redigo
JavaJedis, Lettuce, Redisson
Pythonredis-py, walrus
Scalascala-redis

可点击查看更多支持的编程语言和客户端。

2 环境准备

2.1 安装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

2.2 Java工程依赖包

如果读者使用Maven维护Java工程的话,可以在pom.xml文件中添加如下依赖包。

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

3 Jedis使用方法

3.1 Jedis的基本使用方法

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");
    }
}

3.2 Jedis基本数据结构的使用方法

从上面的代码可以看出,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);
    }
}

3.3 Jedis的事务处理

和关系型数据库类似,Redis也支持事务处理。使用事务处理功能能为客户端提供:

  1. 原子性(Atomicity)。即在一个事务中,要么所有的操作全部顺序执行,要么全部不执行;
  2. 事务隔离(Isolation)。即当一个客户端在运行一个事务时,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();
    }
}

3.4 Pipelining(流水线)

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()方法获得结果
    }
}

3.5 发布者/订阅者

发布者/订阅者模式是由发布者和订阅者两个角色组成的。下面的第一个程序扮演的是订阅者。它通过使用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");
    }
}

4 小结

本章首先介绍了Redis客户端支持的流行的编程语言以及函数库。然后,使用了Jedis库作为Java客户端的一个例子,讲述了Redis编程的常用场景。

 

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.