Redis客户端

前言

通过《redis功能实现》的了解,并且redis官方提供了《JAVA Redis客户端》。其中Jedis,lettuce提供对redis基本封装, redisson为高级封装。

Jedis

jedis主要采用连接池+bio的方式完成jedis的通试。

  1. Jedis.keys方法
// redis.clients.jedis.Jedis最终会调用以下方法
// redis.clients.jedis.Connection
public void sendCommand(final ProtocolCommand cmd, final byte[]... args) {
    try {    
          // 以bio的方式连接
          connect();
          // 组装命令向outputStream写入协议
          Protocol.sendCommand(outputStream, cmd, args);
    } catch (JedisConnectionException ex) {
      // ...
    }
}
  1. JedisPool连接池接入
// JedisPool最终会通过些访求进行初始化
// poolConfig 实现类 JedisPoolConfig 主要提供连接commons.pool2连接池的配置参数
// factory 实现类 RedisPooledObjectFactory 主要实现commons.pool2资源创建接口PooledObjectFactory
public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {

    this.internalPool = new GenericObjectPool<>(factory, poolConfig);
}
  1. JedisPool例子
public static void main(String[] args) throws Exception {
        JedisPool jedisPool = new JedisPool("localhost", 6379);
        // 不可以多线程使用
        Jedis jedis = jedisPool.getResource();
        System.out.println(jedis.get("foo"));
        jedis.close();
}

lettuce

lettuce使用netty + nio,复用同一个连接。《netty连接redis例子

  1. 通过PlainChannelInitializer实现ChannelInitializer接入netty
  2. CommandHandler 为核心的命令入口
  3. 通过ArrayDeque<RedisCommand<?, ?, ?>> stack 并结合CompletableFuture实现命令的发送和接收的关系
 public static void main(String[] args) throws Exception {
        RedisURI redisUri = RedisURI.Builder.redis("localhost")
                .withDatabase(1)
                .build();
        RedisClient client = RedisClient.create(redisUri);
        // connection普通命令多线程复用,但是使用事务不可以
        StatefulRedisConnection<String, String> connection = client.connect();
        RedisCommands<String, String> sync = connection.sync();
        System.out.println(sync.get("foo"));
        connection.close();
}

Redisson

redisson也是使用netty + nio,复用同一个连接。《netty连接redis例子

  1. 通过RedisChannelInitializer实现ChannelInitializer接入netty
  2. CommandDecoder,CommandEncoder 为核心的命令入口
  3. 通过CommandsQueue 并结合CompletableFuture 子类 RPromise 实现命令的发送和接收的关系
 public static void main(String[] args) {
        RedisClientConfig redisClientConfig = new RedisClientConfig();
        redisClientConfig.setAddress("redis://127.0.0.1:6379");
        RedisClient client = RedisClient.create(redisClientConfig);

        //  connection普通命令多线程复用,但是使用事务不可以
        RedisConnection redisConnection = client.connect();
        // 封装了个命令对象
        // @see RedisCommands.SET
        RedisCommand<String> SET = new RedisCommand<>("SET");
        String setValue = redisConnection.sync(SET, "foo", "yoyo1");
        System.out.println(setValue);
        RedisCommand<String> GET = new RedisCommand<>("GET");
        String value = redisConnection.sync(GET, "foo");
        System.out.println(value);
}

三架构对比

针对redis java client,从多角度进行选型对比

Jedis Lettuce Redisson
地址 https://github.com/xetorthio/jedis https://lettuce.io/ https://github.com/redisson/redisson
what 且健全的redis java客户端,支持redis的所有特性和命令,如事务、管道、发布订阅。 线程安全的redis客户端,封装同步、异步、交互API。不执行阻塞和事务操作时,多线程可共享连接。 线程安全的redis客户端,支持多场景,提供基于redis的某些分布式服务解决方案
实现与使用 实现简单,使用简单 实现较复杂,使用简单 实现复杂,使用简单
网络 阻塞IO Netty Netty
redis命令特性支持 redis命令与特性提供健全的支持 redis命令与特性支持 redis命令和特性支持
抽象封装程度 没有做特别的抽象,特性使用是否正确依赖使用者。 同步、异步、交互场景封装 丰富的数据模型、分布式服务、特性的封装,第三方框架的扩展实现
操作的维度 指令维度的操作 指令维度的操作 使用对象、服务将redis指令和业务分离,对象维度的操作,使用更方便,没有使用指令灵活,支持redisClient执行指令;分布式服务特性缺乏管理平台。
redis连接 每次操作均需要从连接池中获取连接,线程间不可以共享连接,高并发时需要考虑连接过多对client和server的影响。 共享连接,连接是long-lived和线程安全的,而且自动重连 共享连接
client分片 支持,提供实现 不支持,未提供实现 不支持,针对特殊数据模型提数据分片
read slave 未找到使用slave执行read指令的API,但可以自行实现 支持slave执行read指令 支持slave执行read指令
排他+超时 支持 支持 需要使用封装的数据模型
社区维护 社区维护好,版本更新快 社区维护一般,版本更新较慢 分为企业版和开源版,维护好,版本更新快

推荐直接使用Redisson

上一篇:Redis学习


下一篇:jedis五种数据类型的方法解释