5. Java客户端

5.1 简介

Java的Redis客户端(如Jedis、Lettuce)通过封装Redis协议,允许Java应用与Redis服务器交互。它们提供直观的API执行数据操作,支持连接池、集群、哨兵等部署模式。其中Jedis轻量高效但线程不安全,需配合连接池使用;Lettuce基于Netty实现异步与线程安全Redisson专注分布式服务。开发者可根据性能、线程模型和功能需求灵活选用。

5.2 Jedis

5.2.1 简介

Jedis 是一款轻量级、同步阻塞的 Java Redis 客户端,通过直连模式与 Redis 服务器通信。其 API 直接映射 Redis 原生命令(如 set() 对应 SET 指令),学习成本低且稳定性强;但原生线程不安全(多线程需依赖连接池),适用于并发要求不高的传统项目或小型应用,是 Java 生态中最经典的 Redis 集成方案之一。

5.2.2 特点

  • 优点:
    Jedis 设计小巧,实现简洁,稳定性高。其最大优势在于 API 与 Redis 原生命令高度一致:方法名和参数直接对应官方文档指令。这使得开发者遇到不熟悉的操作时,无需额外学习客户端封装,直接查阅 Redis 命令文档即可快速上手,显著降低了学习成本。相比之下,某些客户端重命名 API 的做法虽意图简化,实则增加了额外的记忆负担。

  • 缺点:
    Jedis 采用直连模式且非线程安全。其核心问题在于:单个 Jedis 实例内的 RedisOutputStream (写流) 和 RedisInputStream (读流) 是共享的全局资源。当多个线程并发操作同一实例时,会争抢这些流资源,导致读写数据混乱(如数据错位、混合),而非 Redis 服务本身的数据安全问题。

5.2.3 Jedis 的使用

  • 引用依赖
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>3.7.0</version>
</dependency>
  • 建立连接
private Jedis jedis;
@Before // 该注解,表示在所有你创键的测试方法前先执行,这里用于建立连接
public void setUp() throws Exception {
    jedis = new Jedis("192.168.195.132", 6379); //建立连接
    jedis.auth("123456"); //密码
    jedis.select(0); //选择库
}
  • 使用 Jedis
@Test
public void testString() {
    //命令名和 Redis 的一致 
    String s = jedis.set("name", "tom");
    String name = jedis.get("name");
}
  • 释放资源
@After // 该注解,表示在所有你创键的测试方法后执行,这里用于关闭连接
public void tearDown() throws Exception {
    // 如果在建立连接的时候抛出了异常,那么运行到这的时就会有空指针异常的风险
    if(jedis != null) {
        jedis.close();
    }
}

5.2.4 Jedis连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗。所以建议使用 Jedis 的连接池来代替 Jedis的直连方式。

public class JedisConnectionFactory {
    private static JedisPool jedisPool;
    static {
        //配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        //最大连接量,表示最多建立8个连接
        poolConfig.setMaxTotal(8); 
        //最大空闲连接,表示即便没有线程访问我这个池子,也会最多预备8个连接
        poolConfig.setMaxIdle(8); 
        //最小空闲连接,表示空闲连接存放一段时间后,会被自动释放,直到预备连接小于等于2个
        poolConfig.setMinIdle(2); 
        //最长等待时间,表示当连接池内没有空闲连接时,线程对多等多久后放弃等待
        poolConfig.setMaxWaitMillis(1000); 
        
        //建立连接
        jedisPool = new JedisPool(poolConfig,
                "192.168.195.132", 6379, 1000, "123456");
    }
   
    // 获取连接
    public static Jedis getJedis() {
         return jedisPool.getResource();
    }
}

5.3 SpringDataRedis

5.3.1 简介

  • Spring Data Redis 是 Spring 生态的 Redis 集成框架,内部整合来 Jedis 和 Lettuce。
  • 提供了RedisTemplate统一 API 来操作 Redis。
  • 简化数据操作(自动处理序列化/连接管理)
  • 支持事务、发布订阅、集群与哨兵模式,并天然适配 Spring 事务管理,显著降低 Java 应用访问 Redis 的复杂度,适用于需与 Spring 深度整合的中大型项目。

5.3.2 SpringDataRedis的使用

**SpringBoot 已经整合 SpringDataRedis,并且实现了自动装配,使用起来非常方便,**所以下面我们基于SpringBoot 来使用 SpringDataRedis

  • 引入依赖
<!--redis起步依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--连接池依赖-->
<!--无论是 Jedis 还是 Luttce,都是基于 commons-pool 来实现连接池的效果 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  • 连接和连接池配置
spring:
  data:
    redis:
      host: 192.168.195.132 #连接的虚拟机的 IP 地址
      port: 6379 #端口号
      database: 0 #连接的数据库
      password: 123456 #密码
      lettuce:
        pool: #连接池的配置
          max-active: 8 #最大连接数
          max-idle: 8 #最大空闲连接数
          min-idle: 0 #最小空闲连接数
          max-wait: 100ms #最大等待时间
          #具体解释可以看 Jedis 配置连接池那一节
  • 测试代码
@SpringBootTest
class RedisDemoApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void stringTest() {
        redisTemplate.opsForValue().set("name", "虎哥");
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println(name);
    }
}

5.3.3 RedisTemplated的缺点

RedisTemplate 可以存储任意类型的数据,原因是在存储之前会先把存储的数据序列化字节形式,默认采用的 JDK 序列化。但是得到的结果,可读性差,并且占用了更多的内存

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3.3 解决方式

RedisTemplate 的缺点产生原因在于他默认的序列化方式不太合适,所以我们可以更改他的序列化方式即可解决这个问题。

存在的小问题以及解决办法

  • 但是这种方式还是存在一点点问题就是,他 Value 使用的是 Json 序列化器,当存入和获取的数据类型是对象是会自动序列化和反序列化,但是要实现自动反序列化,存入 Redis 的数据数据需要加一段额外的信息来记录该 Json 数据属于哪个对象,这样就造成了,内存的额外开销。
  • 解决方式也很简单,就是再一次跟换 Value 的序列化方式,采用和 Key 一样的 String 序列化器,但是后果就是,存入数据类型只能是 String 类型。但是没关系,只要当我们要存入对象时,就先将他转为 Json 字符串格式
  • 但是幸运的是我们不要自己再去修改,RedisTemplate 的 Value 的序列化方式了。这个别人已经写好了。Spring 提供了一个 StringRedisTemplate 类,他的 Key 和 Value 默认的序列化方式就是 String 序列化,省去了我们自己定义 RedisTemplate。

5.3.4 StringRedisTemplate

5.3.4.1 简介

为了节省空间我们并不会使用 Json 的序列化器来处理 value,而是统一的使用 String 的序列化器,要求只能存储String 类型的 key 和 value。当需要存储 Java 对象的时候,需手动完成对象序列化和反序列化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3.4.2 使用步骤

至于序列化工具,使用自己喜欢的就好,我这里使用的 FastJson

  • 导入依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.7</version>
</dependency>
  • 代码演示
@Autowired
private StringRedisTemplate stringRedisTemplate;

@Test
void objectTest() {
    User user = new User("name", "虎哥");
    
    //手动序列化(object -> Json)
    String s = JSON.toJSONString(user);
    stringRedisTemplate.opsForValue().set("user:100", s);
    String s1 = stringRedisTemplate.opsForValue().get("user:100");
    
    //手动反序列化(Json -> object)
    User user1 = JSON.parseObject(s1, User.class);
    System.out.println(user1);
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐