• 【Redis破障之路】四:Jedis基本使用


    在前面我们已经学习了Redis命令行客户端redis-cli的使用,接下来我们了解一下Redis基于Java编程语言的客户端。

    在Java语言体系下,有三个常用的Redis客户端JedisRedissonLettuce。三者各有特点,各有适用的场景。

    Java Redis客户端

    • Jedis:Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;

      Jedis中的方法调用是比较底层的暴露的Redis的API,也即Jedis中的Java方法基本和Redis的API保持着一致,了解Redis的API,也就能熟练的使用Jedis。

    • Redisson:实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

      Redisson中的方法则是进行比较高的抽象,每个方法调用可能进行了一个或多个Redis方法调用。

    • Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。是SpringBoot2.x版本默认的客户端。

    好了,我们开始学习Jedis的使用吧。

    1、Jedis的基本使用

    创建Maven工程,在项目中添加Jedis依赖。

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

    Jedis的使用方法非常简单,只要三行代码就可以实现基本的set/get功能:

            //1.生成一个Jedis对象,这个对象负责和指定Redis实例进行通信
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            // 2.jedis执行set操作
            jedis.set("hello", "world");
            //3.jedis执行get操作,value="world"
            String value = jedis.get("hello");
    

    初始化Jedis需要两个参数:Redis实例的IP和端口,除了这两个参数外,还有一个包含了四个参数的构造函数是比较常用的:

    Jedis(final String host, final int port, final int connectionTimeout, final int soTimeout)
    

    参数说明:

    • host:Redis实例的所在机器的IP
    • port:Redis实例的端口
    • connectionTimeout:客户端连接超时
    • soTimeout:客户端读写超时

    可以打印输出一下上面程序的结果:

    运行结果

    和JDBC类似,一般涉及到这种网络I/O的操作,最好使用try catch finally的形式,稍微修改一下上面的例子:

            Jedis jedis = null;
            try {
                jedis = new Jedis("127.0.0.1", 6379);
                jedis.get("hello");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
    

    接下来我们看一下Jedis对各种基本数据类型的操作:

    • 字符串
            jedis.set("hello", "world");
            //结果 world
            System.out.println(jedis.get("hello"));
           //结果 1
            System.out.println(jedis.incr("counter"));
    

    • hash
            jedis.hset("myhash", "f1", "v1");
            jedis.hset("myhash", "f2", "v2");
            //运行结果 {f2=v2, f1=v1}
            System.out.println(jedis.hgetAll("myhash"));
    
    • list
            jedis.rpush("mylist", "1");
            jedis.rpush("mylist", "2");
            jedis.rpush("mylist", "3");
            //运行结果 [1, 2, 3]
            System.out.println(jedis.lrange("mylist",0,-1));
    
    • set
            jedis.sadd("myset", "a");
            jedis.sadd("myset", "b");
            jedis.sadd("myset", "a");
            //运行结果 [b, a]
            System.out.println(jedis.smembers("myset"));
    
    • zset
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            jedis.zadd("thezset", 99, "tom");
            jedis.zadd("thezset", 66, "peter");
            jedis.zadd("thezset", 33, "james");
            //运行结果 james 33.0 peter 66.0 tom 99.0
            jedis.zrangeWithScores("thezset",0,-1).stream().forEach(s->{
                System.out.print(s.getElement()+" "+s.getScore()+" ");
            });
    

    2、序列化

    在Java中,存储对象一般会进行序列化和反序列化,Jedis本身并不支持序列化。可以引入游戏额第三方的序列化工具,例如XML、Json、谷歌的Protobuf、Facebook的Thrift等等。

    我们以protostuff(Protobuf的Java客户端)为例来进行学习:

    • 引入protostuff依赖
       <properties>
            <protostuff.version>1.0.11</protostuff.version>
        </properties>
        
            <dependency>
                <groupId>com.dyuproject.protostuff</groupId>
                <artifactId>protostuff-runtime</artifactId>
                <version>${protostuff.version}</version>
            </dependency>
            <dependency>
                <groupId>com.dyuproject.protostuff</groupId>
                <artifactId>protostuff-core</artifactId>
                <version>${protostuff.version}</version>
            </dependency>    
    
    • 定义实体类
    public class Club implements Serializable {
        private int id; // id
        private String name; // 名称
        private String info; // 描述
        private Date createDate; // 创建日期
        private int rank; // 排名
        //省略getter/setter等
    }    
    
    • 测试序列化和反序列化
            // 1.生成序列化工具类
            ProtostuffSerializer protostuffSerializer = new ProtostuffSerializer();
            // 2.生成Jedis对象
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            // 3.序列化
            String key = "club:1";
            // 定义实体对象
            Club club = new Club(1, "AC", "米兰", new Date(), 1);
            // 序列化
            byte[] clubBtyes = protostuffSerializer.serialize(club);
            jedis.set(key.getBytes(), clubBtyes);
            // 4.反序列化
            byte[] resultBtyes = jedis.get(key.getBytes());
            Club resultClub = protostuffSerializer.deserialize(resultBtyes);
            //结果 Club{id=1, name='AC', info='米兰', createDate=Sat May 15 22:21:42 CST 2021, rank=1}
            System.out.println(resultClub.toString());
    

    3、Jedis连接池

    在上面我们使用的是Jedis的直连方式,每次都会新建TCP 连接,使用后再断开连接。

    这种频繁的连接/断开连接的过程显然是对资源的一种浪费。

    Jedis直连Redis

    和数据库连接池一样,同样可以引入池化技术,将Jedis连接存在池子(JedisPool)里,每次去池子里取,而不用重新创建。

    Jedis连接池使用

    连接池的方式是可以预先初始化好Jedis连接,所以每次只需要从 Jedis连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。

    Jedis提供了JedisPool这个类作为对Jedis的连接池,同时使用了Apache的通用对象池工具common-pool作为资源的管理工具。

    使用JedisPool操 作Redis示例如下:

    1)Jedis连接池(通常JedisPool是单例的):

            // common-pool连接池配置,这里使用默认配置
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
            // 初始化Jedis连接池
            JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
    

    2)获取Jedis对象不再是直接生成一个Jedis对象进行直连,而是从连接池直接获取:

            Jedis jedis = null;
            try {
                // 1. 从连接池获取jedis对象 
                jedis = jedisPool.getResource();
                // 2. 执行操作 
                jedis.get("hello");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    // 如果使用JedisPool,close操作不是关闭连接,代表归还连接池 
                    jedis.close();
                }
            }
    

    面GenericObjectPoolConfig使用的是默认配置,实际它提供有很多参数,例如池子中最大连接数、最大空闲连接数、最小空闲连接数、连接活性检测,等等。




    参考:

    【1】:《Redis开发与运维》

    【2】:redis几种java客户端比较

  • 相关阅读:
    常用控件的学习
    C# NOSQL 开源项目
    Js生成Guid
    通过sql语句附加数据库与启用sa账户
    Js 键值对实现
    sqlServer2000 安装备忘
    System.Reflection.ReflectionTypeLoadException: 无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性。
    关于ado.net连接池的一些分享(2)(原文出自:http://www.cnblogs.com/b42259626/articles/968460.html)
    关于ado.net连接池的一些分享(原文出自:http://www.cnblogs.com/rickie/archive/2004/10/02/48546.aspx)
    删除迅雷文件夹
  • 原文地址:https://www.cnblogs.com/three-fighter/p/14784734.html
Copyright © 2020-2023  润新知