Spring Data Redis 集成了 Jedis 与 lettuce,但有些企业仍在使用 Jedis 而没有用 Spring Data Redis

  • Jedis:以 Redis 命令作为方法名称,学习成本低,简单实用。但是 Jedis 实例是线程不安全的,多线程环境下需要基于连接池来使用
  • Lettuce:Lettuce 是基于 Netty 实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持 Redis 的哨兵模式、集群模式和管道模式。

# Jedis

Jedis 使用的基本步骤:

  1. 引入依赖
  2. 创建 Jedis 对象,建立连接
  3. 使用 Jedis,方法名与 Redis 命令一致
  4. 释放资源
//1. 引入依赖
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>
//2. 建立连接
private Jedis jedis;
@BeforeEach
void setUp() {
    // 建立连接
    jedis = new Jedis("192.168.150.101", 6379);
    // 设置密码
    jedis.auth("123321");
    // 选择库
    jedis.select(0);
}
//3. 测试 string
@Test
void testString() {
    // 插入数据,方法名称就是 redis 命令名称,非常简单
    String result = jedis.set("name", "张三");
    System.out.println("result = " + result); 
    // 获取数据
    String name = jedis.get("name");
    System.out.println("name = " + name);
}
//4. 释放资源
@AfterEach
void tearDown() {
    // 释放资源
    if (jedis != null) {
        jedis.close();
    }
}

# Jedis 连接池

Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐使用 Jedis 连接池代替 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.31.128", 6379,1000, "123321");
    }
    // 获取 Jedis 对象
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

# SpringDataRedis

SpringData Spring 中数据操作的模块,包含对各种数据库的集成,其中对 Redis 的集成模块就叫做 SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis

小提示💡:

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

方案一:

1. 自定义 RedisTemplate

2. 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer

* 方案二:

1. 使用 StringRedisTemplate

2. 写入 Redis 时,手动把对象序列化为 JSON

读取 Redis 时,手动把读取到的 JSON 反序列化为对象

  • 提供了对不同 Redis 客户端的整合(Lettuce 和 Jedis)
  • 提供了 RedisTemplate 统一 API 来操作 Redis
  • 支持 Redis 的发布订阅模型
  • 支持 Redis 哨兵和 Redis 集群
  • 支持基于 Lettuce 的响应式编程
  • 支持基于 JDK、JSON、字符串、Spring 对象的数据序列化及反序列化
  • 支持基于 Redis 的 JDKCollection 实现

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

API返回值类型说明
redisTemplate.opsForValue()ValueOperations操作 String 类型数据
redisTemplate.opsForHash()HashOperations操作 Hash 类型数据
redisTemplate.opsForList()ListOperations操作 List 类型数据
redisTemplate.opsForSet()SetOperations操作 Set 类型数据
redisTemplate.opsForZSet()ZSetOperations操作 SortedSet 类型数据
redisTemplate通用的命令

SpringDataRedis 的使用步骤:

  1. 引入 spring-boot-starter-data-redis 依赖
  2. 在 application.yml 配置 Redis 信息
  3. 注入 RedisTemplate

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:
	redis:
    	host: 192.168.31.128 # 虚拟机地址
        port: 6379
        password: 123321
        lettuce:
            pool:
                max-active: 8 # 最大连接
                max-idle: 8 # 最大空闲连接
                min-idle: 0 # 最小空闲连接
                max-wait: 100 # 连接等待时间

3. 注入 RedisTemplate

@Autowired
private RedisTemplate redisTemplate;

4. 编写测试

@SpringBootTest
public class RedisTest {
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    @Test
    void testString() { 
        // 插入一条 string 类型数据
        redisTemplate.opsForValue().set("name", "李四");
        // 读取一条 string 类型数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }
}

# SpringDataRedis 的序列化方式

RedisTemplate 可以接收任意 Object 作为值写入 Redis,只不过写入前会把 Object 序列化为字节形式,默认是采用 JDK 序列化,得到的结果是这样的: \AC\XED

缺点:

  • 可读性差
  • 内存占用较大

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

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
    throws UnknownHostException {
    // 创建 Template
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    // 设置连接工厂
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 设置序列化工具
    GenericJackson2JsonRedisSerializer jsonRedisSerializer = 
					new GenericJackson2JsonRedisSerializer();
    //key 和 hashKey 采用 string 序列化
    redisTemplate.setKeySerializer(RedisSerializer.string()); 
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    //value 和 hashValue 采用 JSON 序列化
    redisTemplate.setValueSerializer(jsonRedisSerializer);
    redisTemplate.setHashValueSerializer(jsonRedisSerializer);
    return redisTemplate;
}

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

为了在反序列化时知道对象的类型,JSON 序列化器会将类的 class 类型写入 json 结果中,存入 Redis,会带来额外的内存开销。所以产生了使用 StringRedisTemplate 这种解决办法

# *StringRedisTemplate

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

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

@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON 工具
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testStringTemplate() throws JsonProcessingException {
    // 准备对象
    User user = new User("虎哥", 18);
    // 手动序列化
    String json = mapper.writeValueAsString(user);
    // 写入一条数据到 redis
    stringRedisTemplate.opsForValue().set("user:200", json); 
    
    // 读取数据
    String val = stringRedisTemplate.opsForValue().get("user:200");
    // 反序列化
    User user1 = mapper.readValue(val, User.class);
    System.out.println("user1 = " + user1);
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Ruler 微信支付

微信支付

Ruler 支付宝

支付宝