3.Redis的Java客户端

在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/latest/develop/clients/

img

其中Java客户端也包含很多:

img

Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而SpringDataRedis又对这两种做了抽象和封装,因此我们后期会直接以SpringDataRedis来学习。

Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。

1.Jedis客户端

Jedis的官网地址: https://github.com/redis/jedis

1.1. 快速入门

我们先来个快速入门:

1)引入依赖:

<!--jedis-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>
<!--单元测试-->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.7.0</version>
    <scope>test</scope>
</dependency>

2)建立连接

新建一个单元测试类,内容如下:

BeforeEach

@BeforeEach 是 JUnit 5 测试框架中的一个注解,用于在每个测试方法执行之前运行一些初始化代码。

使用场景

初始化数据或状态。

重置某些对象的状态。

准备测试资源,比如数据库连接、文件等。

@BeforeEach 是一个非常有用的注解,可以让你专注于测试逻辑,而不用担心每次重复编写初始化代码,提高了测试代码的可维护性和清晰性。

private Jedis jedis;

@BeforeEach
void setUp() {
    // 1.建立连接
    // jedis = new Jedis("192.168.150.101", 6379);
使用连接池创建!!!!
    jedis = JedisConnectionFactory.getJedis();
    // 2.设置密码
    jedis.auth("123321");
    // 3.选择库
    jedis.select(0);
}

3)测试:

@Test
void testString() {
    // 存入数据
    String result = jedis.set("name", "虎哥");
    System.out.println("result = " + result);
    // 获取数据
    String name = jedis.get("name");
    System.out.println("name = " + name);
}

@Test
void testHash() {
    // 插入hash数据
    jedis.hset("user:1", "name", "Jack");
    jedis.hset("user:1", "age", "21");

    // 获取
    Map<String, String> map = jedis.hgetAll("user:1");
    System.out.println(map);
}

AfterEach和BeforeEach功能类似

4)释放资源

@AfterEach
void tearDown() {
    if (jedis != null) {
        jedis.close();
    }
}

1.2. 连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。

下面代码说明

定义了一个工具类—— JedisConnectionFactory

一个静态成员变量—— jedisPool

然后通过一个静态代码块(通常用于在类被加载时完成一些静态变量的初始化),对jedisPool初始化

提供一个静态方法,方便从连接池去获取Jedis对象——调用工具类的getJedis方法,从池子中去获取Jedis实例(对象),用完再还回去,避免频繁的创建和销毁

public class JedisConnectionFactory {
    private static final JedisPool jedisPool;
    
    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大连接
        jedisPoolConfig.setMaxTotal (8) ;
        // 最大空闲连接
        jedisPoolConfig.setMaxIdle(8);
        // 最小空闲连接
        jedisPoolConfig.setMinIdle(0);
        // 設置最长等待时间,ms
        jedisPoolConfig.setMaxWaitMillis (200);
        jedisPool = new JedisPool(jedisPoolConfig, "192.168.150.101", 6379,1000, "123321") ;
}
    // 获取Jedis对象
    public static Jedis getJedis(){
        return jedisPool. getResource();
    }
}
package com.chinhae.jedis.util;  
  
import redis.clients.jedis.Jedis;  
import redis.clients.jedis.JedisPool;  
import redis.clients.jedis.JedisPoolConfig;  
  
/**  
 * 这个类是:  
 *  
 * @author: CHINHAE  
 * @date: 2025/10/11 13:07  
 * @version: 1.0  
 */public class JedisConnectionFactory {  
    private static final JedisPool jedisPool;  
  
    static {  
        // 配置连接池  
        JedisPoolConfig poolConfig = new JedisPoolConfig();  
        poolConfig.setMaxIdle(10);  
        poolConfig.setMaxTotal(10);  
        // 创建连接池对象  
        jedisPool = new JedisPool(poolConfig,"47.109.92.14",  
                6379,1000,"Qiu@CHINHAE!");  
    }  
  
    public static Jedis getJedis(){  
        return jedisPool.getResource();  
    }  
}
package com.chinhae.test;  
  
import com.chinhae.jedis.util.JedisConnectionFactory;  
import org.junit.jupiter.api.AfterEach;  
import org.junit.jupiter.api.BeforeEach;  
import org.junit.jupiter.api.Test;  
import redis.clients.jedis.Jedis;  
  
import java.util.Map;  
  
/**  
 * 这个类是:  
 *  
 * @author: CHINHAE  
 * @date: 2025/10/11 12:52  
 * @version: 1.0  
 */public class JedisTest {  
    private Jedis jedis;  
  
    @BeforeEach  
    void setUp() {  
        // 1.建立连接  
        //jedis = new Jedis("47.109.92.14", 6379);  
        jedis = JedisConnectionFactory.getJedis();  
        // 2.设置密码  
        jedis.auth("Qiu@CHINHAE!");  
        // 3.选择库  
        jedis.select(0);  
    }  
  
    @Test  
    void testString() {  
        // 存入数据  
        String result = jedis.set("test01", "胡歌");  
        System.out.println("result = " + result);  
        // 获取数据  
        String test01 = jedis.get("test01");  
        System.out.println("test01 = " + test01);  
    }  
  
    @Test  
    void testHash() {  
        jedis.hset("user:1", "name", "告诉");  
        jedis.hset("user:1","age","21");  
  
        // 获取  
        Map<String, String> map = jedis.hgetAll("user:1");  
        System.out.println("map = " + map);  
    }  
  
    @AfterEach  
    void tearDown() {  
        if (jedis != null) {  
            jedis.close();  
        }  
    }  
}

2. Spring Data Redis

官网地址: https://spring.io/projects/spring-data-redis

CleanShot 2025-10-11 at 13.24.24@2x.png

2.1. SpringDataRedis快速入门

SpringData Redis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

CleanShot 2025-10-11 at 14.21.19@2x.png

SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:

1.引入依赖

<!--Redis依赖-->  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-data-redis</artifactId>  
</dependency>  
<!--连接池依赖-->  
<dependency>  
    <groupId>org.apache.commons</groupId>  
    <artifactId>commons-pool2</artifactId>  
</dependency>

2.配置文件

spring:  
  data:  
    redis:  
      host: 47.109.92.14  
      port: 6379  
      password: Qiu@CHINHAE!  
      lettuce:  
        pool:  
          max-active: 8  
          max-idle: 8  
          min-idle: 0  
          max-wait: 100ms

3.注入RedisTemplate,编写测试

package com.chinhae;  
  
import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.data.redis.core.RedisTemplate;  
  
@SpringBootTest  
class SpringDataRedisDemoApplicationTests {  
  
    @Autowired  
    private RedisTemplate redisTemplate;  
  
    @Test  
    void testString() {  
        // 写入一条String数据  
        redisTemplate.opsForValue().set("name","虎哥");  
        // 获取string数据  
        Object name = redisTemplate.opsForValue().get("name");  
        System.out.println("name = " + name);  
    }  
  
}

会发现存入的数据是这样的乱码

CleanShot 2025-10-11 at 15.00.41@2x.png

就需要自定义RedisTemplate的序列化来显示了

2.2 SpringDataRedis的序列化方式

我们可以自定义RedisTemplate的序列化方式,代码如下:

package com.chinhae.redis.config;  
  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.data.redis.connection.RedisConnectionFactory;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;  
import org.springframework.data.redis.serializer.RedisSerializer;  
  
/**  
 * 这个类是:  
 *  
 * @author: CHINHAE  
 * @date: 2025/10/11 15:01  
 * @version: 1.0  
 */@Configuration  
public class RedisConfig {  
  
    @Bean  
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {  
        // 创建RedisTemplate对象  
        RedisTemplate<String, Object> template = new RedisTemplate<>();  
        // 设置连接工厂  
        template.setConnectionFactory(connectionFactory);  
        // 创建JSON序列化工具  
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();  
        // 设置Key的序列化  
        template.setKeySerializer(RedisSerializer.string());  
        template.setHashKeySerializer(RedisSerializer.string());  
        // 设置Value的序列化  
        template.setValueSerializer(jsonRedisSerializer);  
        template.setHashValueSerializer(jsonRedisSerializer);  
        // 返回  
        return template;  
    }  
}

测试:

package com.chinhae;  
  
import com.chinhae.redis.entity.User;  
import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.data.redis.core.RedisTemplate;  
  
@SpringBootTest  
class SpringDataRedisDemoApplicationTests {  
  
    @Autowired  
    private RedisTemplate<String,Object> redisTemplate;  
  
    @Test  
    void testString() {  
        // 写入一条String数据  
        redisTemplate.opsForValue().set("name","虎哥");  
        // 获取string数据  
        Object name = redisTemplate.opsForValue().get("name");  
        System.out.println("name = " + name);  
    }  
  
    @Test  
    void testSaveUser() {  
        // 写入数据  
        redisTemplate.opsForValue().set("user:100",new User("虎哥",21));  
        // 获取数据  
        User o = (User)redisTemplate.opsForValue().get("user:100");  
        System.out.println("o = " + o);  
    }  
}
package com.chinhae.redis.entity;  
  
import lombok.AllArgsConstructor;  
import lombok.Data;  
import lombok.NoArgsConstructor;  
  
/**  
 * 这个类是:  
 *  
 * @author: CHINHAE  
 * @date: 2025/10/11 15:13  
 * @version: 1.0  
 */@Data  
@NoArgsConstructor  
@AllArgsConstructor  
public class User {  
    private String name;  
    private Integer age;  
}

2.3 StringRedisTemplate

尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:

CleanShot 2025-10-11 at 15.23.38@2x.png

为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。

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

CleanShot 2025-10-11 at 15.26.01@2x.png

Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程:

package com.chinhae;  
  
import com.chinhae.redis.entity.User;  
import com.fasterxml.jackson.core.JsonProcessingException;  
import com.fasterxml.jackson.databind.ObjectMapper;  
import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.data.redis.core.StringRedisTemplate;  
  
@SpringBootTest  
class SpringDataRedisDemoStringTests {  
  
    @Autowired  
    private StringRedisTemplate stringRedisTemplate;  
  
    @Test  
    void testString() {  
        // 写入一条String数据  
        stringRedisTemplate.opsForValue().set("name","虎哥");  
        // 获取string数据  
        Object name = stringRedisTemplate.opsForValue().get("name");  
        System.out.println("name = " + name);  
    }  
  
    private static final ObjectMapper mapper = new ObjectMapper();  
  
    @Test  
    void testSaveUser() throws JsonProcessingException {  
        // 创建对象  
        User user = new User("虎哥", 21);  
        // 手动序列化  
        String json = mapper.writeValueAsString(user);  
        // 写入数据  
        stringRedisTemplate.opsForValue().set("user:200",json);  
        // 获取数据  
        String jsonUser = stringRedisTemplate.opsForValue().get("user:200");  
        // 手动反序列化  
        User user1 = mapper.readValue(jsonUser, User.class);  
        System.out.println("user1 = " + user1);  
    }  
}

RedisTemplate的两种序列化实践方案:

方案一:

  1. 自定义RedisTemplate
  2. 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer

方案二:

  1. 使用StringRedisTemplate
  2. 写入Redis时,手动把对象序列化为JSON
  3. 读取Redis时,手动把读取到的JSON反序列化为对象
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇