Redis基础(五)之Jedis操作

228 阅读9分钟

第五章、Jedis操作【重点】

1、jedis介绍

我们之前在学习mysql数据库的时候,我们也是通过dos窗口连接mysql数据库服务器,然后使用SQLYog图形化界面操作mysql数据库服务器,最后学习了使用JDBC操作mysql数据库服务器。同理我们学习完使用dos窗口和图形化界面操作完redis数据库服务器之后,接下来我们要学习使用java代码如何操作redis数据库服务器。

我们可以访问redis官网,看下官网对操作redis数据库服务器的客户端的介绍:

redis.io/

1.找客户端

image-20200212125949720.png

2.找星标记和笑脸标记

image-20200212130051210.png

3.点击java

image-20200212130153242.png

4.选择jedis

image-20200212130559726.png

Jedis:java客户端技术-操作redis服务中的数据

2、Jedis的使用

目标

  1. Jedis类和方法的介绍
  2. Jedis的使用案例

Jedis的介绍

Redis不仅可以使用命令来操作,现在基本上主流的语言都有API支持,比如Java、C#、C++、PHP、Node.js、Go等。

在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis等其中官方推荐使用Jedis和Redisson。 使用Jedis操作redis需要导入核心jar包如下:

image-20200212215025814.png 或者导入maven的依赖:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.7.0</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>

Jedis类常用方法

注:每个方法就是redis中的命令名,方法的参数就是命令的参数。

在每次访问Redis数据库的时候,都需要创建一个Jedis对象。每个Jedis对象似于JDBC中Connection对象,类似于mybatis中session对象。

连接和关闭功能
new Jedis(host, port)创建Jedis连接对象,参数: host: 服务器地址 port:端口号6379
void close()关闭连接
对string操作的方法说明
set(String key,String value)添加字符串类型的键和值
String get(String key)通过键得到字符串的值
del(String ... keys)删除一个或多个键
对hash操作的方法说明
hset(String key,String field,String value)添加一个hash类型的键,字段和值
Map<String,String> hgetall(String key)通过一个键得到所有的字段和值,返回Map
对list操作的方法说明
lpush(String key,String...values)从左边添加多个值到list中
List lrange(String key,long start,long end)通过键得到指定范围的元素
对set操作的方法说明
sadd(String key,String...values)添加一个或多个元素
Set smembers(String key)通过键得到集合所有的元素
对zset操作的方法说明
zadd(String key, double score, String member)添加一个键,分数和值
Set zrange(String key, long start, long end)查询一个指定范围的元素

3、案例:Jedis的基本操作

目标

使用Jedis上面的方法来访问Redis,向服务器中写入字符串、hash和list类型,并且取出打印到控制台上。

操作步骤:

1.创建maven的java工程

image-20200913100349359.png

image.png

image.png

image.png

2.创建maven的web工程 image.png

image-20200913101151333.png

image-20200913102846907.png

image-20200913103022844.png

image-20200913103013652.png

image-20200913103201958.png

image-20200212165832733.png

将依赖导入到pom.xml文件中:

 <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.0</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
</dependencies>
​
  <!--插件管理-->
    <build>
        <plugins>
            <!--编译插件:jdk1.8-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!-- put your configurations here -->
                    <!--源码-->
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

image.png 3.创建测试类,书写操作redis数据库的代码,代码一共分为三步:

【1】创建jedis对象,连接redis数据库服务器 new Jedis(host,port)

【2】 操作数据

【3】 关闭连接

【1.下面是操作字符串数据的代码】:

package com.hea.sh.jedis_test_01;

import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;

public class JedisTest01 {
    /*
        jedis入门
     */
    @Test
    public void test01(){
        //1.创建jedis对象,连接redis数据库服务器 new Jedis(host,port)
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.操作数据
        //【1】字符串
        jedis.set("username", "柳岩");
        //获取
        String username = jedis.get("username");
        System.out.println("username = " + username);
        //一次性添加多个数据 mset(key1,value1,key2,value2,...)
        jedis.mset("addr", "sh", "company", "啦啦");
        //获取所有的数据
        List<String> values = jedis.mget("username", "addr", "company");
        System.out.println("values = " + values);
        //3.关闭连接
        jedis.close();
    }
}

控制台输出结果:

image.png 小结:

1.一次性添加多个字符串数据,使用的方法如下:

mset(key1,value1,key2,value2,...)

2.一次性获取所有的字符串:

List<String> mget(key1,key2,key3...);

【2.下面是操作hash数据的代码】:

package com.hea.sh.jedis_test_01;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JedisTest01 {
    /*
        jedis入门
     */
    @Test
    public void test01(){
        //1.创建jedis对象,连接redis数据库服务器 new Jedis(host,port)
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.操作数据
       //【2】hash
        jedis.hset("person", "username", "大哥");
        //存储多个数据 注意这里map集合的键和值都是String类型
        Map<String, String> map = new HashMap<>();
        map.put("age", "18");
        map.put("height", "180");
        jedis.hmset("person", map);
        //获取hash中的所有的数据
        Map<String, String> map1 = jedis.hgetAll("person");
        System.out.println(map1);
        //3.关闭连接
        jedis.close();
    }
}

小结:

1.向hash中添加一个数据:

jedis.hset(key, field, value);

2.向hash中添加多个数据:

jedis.hset(key, map集合);

3.获取hash中所有的数据:

Map<String, String> map1 = jedis.hgetAll(key);

【3.下面是操作list数据的代码】:

package com.hea.sh.jedis_test_01;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JedisTest01 {
    /*
        jedis入门
     */
    @Test
    public void test01(){
        //1.创建jedis对象,连接redis数据库服务器 new Jedis(host,port)
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.操作数据
        //【3】list
        jedis.lpush("teac_list", "大哥", "打工人", "打工");
        //获取数据
        List<String> teac_list = jedis.lrange("teac_list", 0, -1);
        System.out.println(teac_list);
        //3.关闭连接
        jedis.close();
    }
}

小结:

1.向list中添加数据:

lpush(key, value1,value2,value3,...);

2.获取list中所有的数据:

lrange(key, 0, -1);

小结

  1. 创建Jedis: new Jedis(host, port)
  2. 添加字符串键: set
  3. 添加list键:lpush
  4. 得到字符串键:get
  5. 得到list所有值:lrange
  6. 关闭连接:close()

4、Jedis连接池的使用

jedis连接池的基本概念

使用jedis连接redis数据库服务器的时候,创建和销毁连接是很消耗程序性能的。尤其是频繁多次操作redis数据库,性能会更低。所以jedis为我们提供了jedis的连接池技术,jedis连接池在创建时初始化一些连接对象存储到连接池中,使用jedis连接资源时不需要自己创建jedis对象,而是从连接池中获取一个资源进行对redis的操作。使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。

1553426021072.png

Jedis连接池API

JedisPoolConfig配置类功能说明
JedisPoolConfig()创建一个配置对象
void setMaxTotal()设置连接池的最大连接数
void setMaxWaitMillis()设置最长等待时间
JedisPool连接池类说明
JedisPool(配置对象,服务器名,端口号)创建一个连接池,参数: 1. 上面的配置对象 2. 服务器名 3. 端口号
Jedis getResource()从连接池中得到一个连接对象Jedis

JedisPool的基本使用

需求:

使用连接池优化jedis操作,从连接池中得到一个创建好的Jeids对象,并且使用这个Jedis对象。从Redis数据库中获取key是username的value值,打印到控制台

连接池使用开发步骤

1.导入Apache提供的连接池依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.3</version>
</dependency>

image-20200913114047790.png 2.在测试方法中创建连接池的配置对象

3.创建连接池

4.从连接池中获取连接

5.使用连接操作数据

6.使用完毕后把连接还回连接池中

入门的执行代码

 /*
        2.在测试方法中创建连接池的配置对象
        3.创建连接池
        4.从连接池中获取连接
        5.使用连接操作数据
        6.使用完毕后把连接还回连接池中
     */
    @Test
    public void test02(){
        //在测试方法中创建连接池的配置对象 **JedisPoolConfig()**
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //创建连接池 **JedisPool(配置对象,服务器名,端口号)**
        JedisPool jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379);
        //从连接池中获取连接
        Jedis jedis = jedisPool.getResource();
        //使用连接操作数据
        String username = jedis.get("username");
        System.out.println("username = " + username);
        //使用完毕后把连接还回连接池中
        jedis.close();
    }
}

运行效果

image-20200212220515080.png

jedis连接池的配置参数

上述代码我们在创建连接池对象的时候使用的都是连接池的默认参数,接下来我们需要学习几个关于连接池比较重要的参数。

演示参数的代码如下:

注意:演示参数的的时候请不要将jedis的连接关闭。这样才可以看到效果。

  /*
        说明:
        1.默认连接池中最多有8个连接
        2.我们可以通过查看JedisPoolConfig源码查看默认最大连接数,然后对其进行修改
            JedisPoolConfig的父类GenericObjectPoolConfig类中的成员变量
             public static final int DEFAULT_MAX_TOTAL = 8;
             DEFAULT_MAX_TOTAL表示默认的最大连接数是8,我们可以使用方法对其更改:
                public void setMaxTotal(int maxTotal)
        3.我们发现如果连接池中的连接都被获取了,还想获取只能等待,如果不设置就会一直等待,
            我们可以通过方法进行设置最大等待时间:public void setMaxWaitMillis(long maxWaitMillis)
            最大等待时间到了,没有获取到就会报错:
            redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
        4.通过查看源码我们发现最大空闲连接数maxIdle和最大连接数值是一致的maxTotal
            如果我们设置最大空闲连接数最好也要和最大连接数一致

     */
    @Test
    public void test03() {
        //在测试方法中创建连接池的配置对象 **JedisPoolConfig()**
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //设置最大连接数
        jedisPoolConfig.setMaxTotal(10);
        //最大等待时间 最大等待时间到了,没有获取到就会报错
        jedisPoolConfig.setMaxWaitMillis(2000);
        //最大空闲连接数
        jedisPoolConfig.setMaxIdle(10);
        //创建连接池 **JedisPool(配置对象,服务器名,端口号)**
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
//        for (int i = 0; i < 10; i++) {
        for (int i = 0; i < 12; i++) {
            //从连接池中获取连接
            Jedis jedis = jedisPool.getResource();
            System.out.println(i+"....jedis = " + jedis);
            //关闭连接
            jedis.close();
        }
        //使用完毕后把连接还回连接池中
        //关闭连接
//        jedis.close();
    }

说明: 1.默认连接池中最多有8个连接 2.我们可以通过查看JedisPoolConfig源码查看默认最大连接数,然后对其进行修改 JedisPoolConfig的父类GenericObjectPoolConfig类中的成员变量 public static final int DEFAULT_MAX_TOTAL = 8; DEFAULT_MAX_TOTAL表示默认的最大连接数是8,我们可以使用方法对其更改: public void setMaxTotal(int maxTotal) 3.我们发现如果连接池中的连接都被获取了,还想获取只能等待,如果不设置就会一直等待, 我们可以通过方法进行设置最大等待时间:public void setMaxWaitMillis(long maxWaitMillis) 最大等待时间到了,没有获取到就会报错: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool 4.通过查看源码我们发现最大空闲连接数maxIdle和最大连接数值是一致的maxTotal 如果我们设置最大空闲连接数最好也要和最大连接数一致

问题:为什么最大空闲连接数最好也要和最大连接数一致?

image-20200212222931343.png 注意:假设maxTotal是100,maxIdle是50.那么连接池刚开始初始化时是50个连接和最大空闲连接一样的。那么如果突然有70个并发的请求,那么连接池中少了20个连接,此时连接池还可以使用50个连接,可以在创建20个连接,但是我们要注意创建新的连接很消耗性能的。那么会造成20个连接等待时间较长,有可能会造成系统并发性很大。所以我们将maxIdle设置为最大连接数就可以了。如果并发数大于最大连接数,那么只能等待了。

小结

JedisPool连接池类作用
JedisPool(配置对象,服务器名,端口号)创建一个连接池
Jedis getResource()从连接池中得到连接对象
void close()关闭连接池

5、案例:编写jedis连接池工具类

我们发现上述代码在给连接池设置最大连接数、最大等待时间、最大空闲连接数、redis服务器ip地址以及端口号都是书写在代码里面了,这样造成硬编码了。那么我们每次修改都要修改源码。并且每次使用jedis连接池获取连接都比较麻烦,所以我们这里可以将最大连接数、最大等待时间、最大空闲连接数、redis服务器ip地址以及端口号放到配置文件中,然后获取连接池的代码放到工具类中,这样就大大简化了代码的开发。

ResourceBundle类

作用:简化了Java属性配置文件的读取。

说明:我们以前都是使用类加载器读取src下的配置文件中的信息。这里我们使用ResourceBundle类来简化类加载器读取配置文件的信息。

java.util.ResourceBundle类功能
static ResourceBundle getBundle("配置文件名")读取指定的配置文件 返回ResourceBundler对象 只需要指定主文件名即可,不用指定扩展名。
String getString("键名")读取配置文件中指定的键,返回相应的值

Jedis连接池工具类的实现

需求:

  1. 实现连接池工具类,通过工具类得到Jedis连接对象,配置参数写在属性文件中
  2. 调用工具类,对Redis数据库进行操作

实现步骤

配置文件

在resources目录下创建连接池的配置文件: jedis.properties

内容如下:

jedis.maxTotal=10
jedis.maxWaitMillis=2000
jedis.maxIdle=10
jedis.host=127.0.0.1
jedis.port=6379

image-20200913120809619.png

工具类创建
  1. 创建静态成员变量JedisPool对象
  2. 在静态代码块中,读取src下的配置文件,得到ResourceBundle对象
  3. 得到上面的四个参数,其中host是字符串类型,其它参数要转成整数类型
  4. 实例化配置对象,实例化连接池对象
  5. 编写静态方法getJedis()返回Jedis对象
package com.hea.sh.util;
​
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
​
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;
​
public class JedisUtil {
    private static JedisPool pool;
    static {
        //1.读取配置参数 只读取一次:【类加载器】 【ResourceBundle】
        /*InputStream inputStream = JedisUtil.class.getClassLoader().getResourceAsStream("jedis.properties");
        Properties p = new Properties();
        p.load(inputStream);
        String maxTotal = p.getProperty("jedis.maxTotal");*/
        //【ResourceBundle】 jedis.properties
        //注意这里只需要书写配置文件名jedis即可
        ResourceBundle bundle = ResourceBundle.getBundle("jedis");
        //根据key获取value
        int maxTotal = Integer.parseInt(bundle.getString("jedis.maxTotal"));
        int maxWaitMillis = Integer.parseInt(bundle.getString("jedis.maxWaitMillis"));
        int maxIdle = Integer.parseInt(bundle.getString("jedis.maxIdle"));
        String host = bundle.getString("jedis.host");
        int port = Integer.parseInt(bundle.getString("jedis.port"));
​
        //2.创建连接池:提前创建,只创建一次
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWaitMillis);
        config.setMaxIdle(maxIdle);
​
        pool = new JedisPool(config,host,port);
    }
    //3.提供连接池
    public static JedisPool getJedisPool(){
        return pool;
    }
    //4.提供方法从连接池中获取连接对象
    public static Jedis getJedis(){
        return pool.getResource();
    }
    //5.释放连接
    public static void closeJedis(Jedis jedis){
        if(jedis != null){
            jedis.close();
        }
    }
}

注意:使用 ResourceBundle bundle = ResourceBundle.getBundle("jedis"); 读取配置文件中的数据,方法这里不用书写后缀名,直接书写文件名即可。

使用工具类

需求:获取redis数据库中key是username的值,并输出到控制台。

【代码实现】

@Test
    public void test04() {
        //1.直接从工具类中获取jedis
        Jedis jedis = JedisUtil.getJedis();
        //2.操作数据
        String username = jedis.get("username");
        System.out.println("username = " + username);
        //3.返回连接
        JedisUtil.closeJedis(jedis);
    }
执行效果

image-20200213003459641.png

小结

java.util.ResourceBundle类作用
static ResourceBundle getBundle("配置文件基名")创建读取属性文件的对象,参数是属性文件基名
String getString("键名")读取指定键的值