Redis基础(6):SpringDataRedis

SpringDataRedis简介

SpringDataSpring中专门进行数据操作的模块,包含了对于各种数据库的集成 。其中对Redis的集成模块叫做SpringDataRedis(官网地址:Spring Data Redis)。其最核心的特点就是提供了不同Redis客户端的整合 :结合了JedisLettuce提供了RedisTemplate这个统一的操作模板来操作Redis ,下图是SpringDataRedis的其他特点:

由于Spring系列的强大生态支持,和SpringDataRedis本身优秀的使用体验,现在越来越多的企业倾向于使用SpringDataRedis作为RedisJava客户端,同时本人也推荐大家使用SpringDataRedis

SpringDataRedis快速入门

引入依赖

我们使用SpringBoot框架来进行SpringBootRedis的快速入门。由于SpringBoot已经提供了对SpringDataRedis的支持(可以在创建SpringBoot项目的时候将SpringDataRedis的依赖引入到pom.xml文件中),所以说使用起来非常的简单 ,如果没有在创建项目时引入依赖,也可以进行手动引入,在引入时不但需要SpringDataRedis的依赖,还需要一个连接池依赖来实现连接池(commons-pool2):

xml 复制代码
<!-- SpringDataRedis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>3.4.6</version>
</dependency>
<!-- 连接池依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version>
</dependency>

配置文件

因为我们使用了SpringBoot框架,所以说对于Redis连接的配置我们可以直接基于application文件进行配置:

yaml 复制代码
spring:
  data:
    redis:
      host: 192.168.181.134
      port: 6379
      password: your password
      # 连接池配置
      lettuce:
        pool:
          max-active: 8 # 最大连接数
          max-idle: 8 # 最大空闲连接
          min-idle: 4 # 最小空闲连接
          max-wait: 1000ms # 连接等待时间

在配置连接池的时候需要特别注意,可以使用JedisLettuce两个连接池:

Spring默认使用的是Lettuce连接池,可以从Maven依赖传递中看出:

而我们并没有引入Jedis的依赖,所以说在配置连接池的时候使用Lettuce即可 ,如果想要使用Jedis连接池,则需要引入对应的依赖。

编码操作

上文提到了SpringDataRedis提供了一个RedisTemplate这个统一的操作模板来操作Redis,所以说想要使用SpringDataRedis只需要学会RedisTemplate即可RedisTemplate中封装了各种对于Redis的操作,并且将不同数据类型的操作API封装到了不同的类型中:

下面是一个简单的RedisTemplate操作示例:

kotlin 复制代码
package com.wzb;

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 RedisSpringDataApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testString() {
        // 存储一条String数据
        redisTemplate.opsForValue().set("name", "jack");
        // 获取String数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println(name);
    }

}

这是一个SpringBoot的测试类,其中通过@Autowired注解注入了RedisTemplate,然后在测试方法中,通过opsForValue来操作String类型的数据 ,并且通过set方法存入一条KeynameValuejack的数据。但是这样存入数据之后,我们是无法正常读取的,让我们通过可视化界面查看一下刚才存入的数据:

我们可以看到在我们原本的Key:name之间有一大串字符,在原本的Value:jack之前也有一大串字符。这是因为RedisTemplate在存入数据之前需要将数据序列化,而默认的序列化器是JdkSerializationRedisSerializer也就是JDK的默认序列化器,该序列化器会将Java对象转换为Java标准的二进制序列化,而那些十六进制的特殊字符是JDK序列化的魔法数 。这样的状况显然不是我们想看到的,因为这样的话存入的Key-Value的值完全被改变了,无法直接进行读取或修改,此时,就需要配置RedisTemplate的序列化器。

配置RedisTemplate的序列化器

通过观察RedisTemplate的源代码发现,RedisTemplate一共可以支持4个序列化器的配置,并且由于这4个序列化器的配置都是null,所以说会使用默认的JdkSerializationRedisSerializer序列化器 。可供选择的Serializer如图所示:

一般对于Key的序列化会使用StringRedisSerializer,而Value的序列化器使用 genericJackson2JsonRedisSerializer这个序列化器会将Java对象转为Json字符串然后再存储到Redis中。

我们可以创建一个类来完成RedisTemplate的序列化器配置:

kotlin 复制代码
package com.wzb.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;

/**
 * Redis序列化设置
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 创建Json序列化工具
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置Key序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // 设置Value序列化
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        // 返回
        return redisTemplate;
    }
    
}

想要使用genericJackson2JsonRedisSerializer序列化器还需要引入Json相关依赖:

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

然后就可以修改原来代码,注入我们自定义序列化器的RedisTemplate

typescript 复制代码
@Autowired
private RedisTemplate<String, Object> redisTemplate;

测试之后发现,存入的数据是我们想要的结果:

然后测试存入一个Java对象:

sql 复制代码
@Test
void testObject() {
    redisTemplate.opsForValue().set("user", new User("zhangsan", 20));
    User user = (User)redisTemplate.opsForValue().get("user");
    System.out.println(user);
}

发现存取都是没有问题的,更换RedisTemplate序列化器成功。

StringRedisTemplate

在使用genericJackson2JsonRedisSerializer序列化器存储一个Java对象时,除了对象的属性外,还会存储这个类的全类名以便于反序列化 。这样看似很方便,但实际上存在一个很大的问题:耗费了太多的额外存储空间 。因为Redis是基于内存的,众所周知,内存是十分宝贵的,所以说要尽量高效地使用内存,将全类名存入Redis是不推荐的做法。

解决方法就是对于Value,也使用和Key一样的StringRedisSerializer序列化器,Value当作String类型进行处理,然后在Java代码中通过程序手动序列化和反序列化Spring早就为我们考虑到了这一点,于是提供了一个StringRedisTemplate工具,其KeyValue的序列化器就是StringRedisSerializer

我们就可以使用StringRedisTemplate来操作,而无需自己去设置序列化器:

java 复制代码
package com.wzb;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzb.pojo.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.StringRedisTemplate;

import java.util.Map;

@SpringBootTest
public class StringRedisTemplateTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final ObjectMapper mapper = new ObjectMapper();

    @Test
    void testSave() throws JsonProcessingException {
        // 创建对象
        User user = new User("lisi", 25);
        // 手动序列化
        String json = mapper.writeValueAsString(user);
        // 写入数据
        stringRedisTemplate.opsForValue().set("user", json);
        // 获取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user");
        // 手动反序列化
        User readUser = mapper.readValue(jsonUser, User.class);
        System.out.println(readUser);
    }

}

使用了StringRedisTemplate之后,需要我们手动进行对象的序列化和反序列化 ,其他的操作和使用RedisTemplate并无差别,但是这样之后,存储一个Java对象就不会再存储其字节码等额外信息了:

这样做会增加额外的代码处理,但是可以极大的节约内存资源,是推荐的做法。

相关推荐
好奇的菜鸟2 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
tan180°2 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
满昕欢喜3 小时前
SQL Server从入门到项目实践(超值版)读书笔记 20
数据库·sql·sqlserver
优创学社24 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
why技术4 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理4 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
Hello.Reader4 小时前
Redis 延迟排查与优化全攻略
数据库·redis·缓存
ai小鬼头5 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github
简佐义的博客5 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
爬山算法5 小时前
MySQL(116)如何监控负载均衡状态?
数据库·mysql·负载均衡