【Redis】Java操作Redis之SpringDataRedis

Redis 支持多种 Java 客户端,以下是一些常见的:

1. Jedis

  • 特点 :
    是 Redis 官方推荐的 Java 客户端,它提供了简单易用的 API,与 Redis 命令一一对应,可以直接使用 Redis 的各种基本操作,如字符串操作(set、get)、哈希操作(hset、hget)等。
    比较轻量级,资源消耗相对较少,适合在对资源要求不高的场景下使用,并且性能较好。
  • 优点 :
    包装了一个完整的 Redis 协议,能够很好地支持 Redis 的数据类型和操作。
    支持 Redis 的持久化、事务、发布 / 订阅等功能,能够满足基本的 Redis 使用需求。
    社区活跃,文档和示例丰富,方便开发者学习和使用。
  • 缺点 :
    需要自己管理连接,没有自动重连机制,如果 Redis 服务器重启或网络中断,需要自己处理重连逻辑。
    对于高并发场景,连接池配置不当可能会导致性能瓶颈,因为需要手动管理连接池的大小和连接的分配。
  • 适用场景 :
    适合 Redis 使用场景较为简单,且对资源消耗和性能要求不是特别苛刻的应用。
    在一些小型项目或者对 Redis 操作不复杂的情况下,可以快速集成和使用。

2. Lettuce

  • 特点 :
    使用了异步、非阻塞的 I/O 操作,能够提供较高的性能,尤其是在高并发场景下表现出色。
    支持 Redis 协议的各个版本,并且能够很好地与 Redis 集群模式和主从模式配合使用,方便在集群环境中进行 Redis 操作。
  • 优点 :
    异步设计使得在处理大量并发请求时能够更有效地利用系统资源,提高了程序的性能和响应速度。
    支持响应式编程模型,可以很好地与 Spring 5 的响应式框架集成,适合构建响应式系统。
    对 Redis 集群的支持较好,能够自动处理节点的添加、删除等集群变化情况。
  • 缺点 :
    学习曲线相对较陡,由于它是基于异步编程模型的,对于习惯了同步编程的开发者来说,可能需要一定的时间来适应。文档和示例相对 Jedis 和 Redisson 等客户端来说还不够完善,可能会在使用过程中一些遇到问题难以快速解决。
  • 适用场景 :
    主要适用于高并发场景,特别是在构建具有高性能要求的分布式系统时,能够充分发挥其异步非阻塞的优势。
    当与 Spring 5 等响应式框架结合使用时,可以构建出更加高效、灵活的响应式应用。

3. Redisson

  • 特点 :
    是一个功能强大的 Redis Java 客户端,它在 Jedis 的基础上进行了封装,提供了更高层次的抽象,使得 Java 开发者可以像使用本地 Java 对象一样使用 Redis 数据结构。
    支持分布式锁、事务、发布 / 订阅、Lua 脚本等 Redis 特性,并且实现了许多分布式场景下的解决方案,如分布式集合、分布式队列等。
  • 优点 :
    提供了丰富的分布式解决方案,使得在分布式系统中使用 Redis 变得更加方便和直观。
    具有良好的文档和示例,易于上手,并且社区支持较好。支持自动重连和重试机制,能够更好地应对网络波动和 Redis 服务器重启等情况。
  • 缺点 :
    由于封装层次较多,可能会带来一定的性能开销,相比 Jedis 等底层客户端,性能稍差。
    对于一些简单的 Redis 操作,使用 Redisson 可能会显得有些繁琐,因为它更侧重于分布式场景下的高级功能。
  • 适用场景 :
    适合在分布式系统中使用 Redis,尤其是在需要实现分布式锁、分布式队列等复杂分布式功能的场景下。当项目需要快速开发分布式相关功能,并且对性能要求不是极其苛刻时,Redisson 是一个不错的选择。

4.SpringDataRedis

Spring Data Redis 是 Spring 提供的一个框架,它让在 Spring 应用里用 Redis 变得超简单。它把底层的 Redis Java 客户端(比如 JedisLettuce)给封装起来,给我们提供了一套统一、好用的 API。

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

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

以下链接是Spring官方提供的Spring data Redis中文学习文档: https://springdoc.cn/spring-data-redis/

快速入门

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

1.RedisTemplate

1.1 导入pom坐标

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.heima</groupId>
    <artifactId>redis-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--common-pool-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!--Jackson依赖-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

1.2 application配置文件

yaml 复制代码
spring:
  redis:
    host: 192.168.88.100 #这里写你配置的redis主机地址
    port: 6379 #默认6379
    password: 1234 #你的密码
    lettuce:
      pool:
        max-active: 8  #最大连接
        max-idle: 8   #最大空闲连接
        min-idle: 0   #最小空闲连接
        max-wait: 1000 #连接等待时间1000ms

1.3 代码测试

java 复制代码
@SpringBootTest
public class RedisDemoApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test() {
        redisTemplate.opsForValue().set("name", "zhangsan");
        System.out.println(redisTemplate.opsForValue().get("name"));
 }

总结

SpringDataRedis的使用步骤:

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

2.1 自定义序列化方式(编写RedisConfig配置类)

RedisTemplate可以接收任意Object作为值写入Redis,但是写入前会把Object序列化为字节形式,Java默认是采用JDK序列化,得到的结果在图形化界面RESP中看是这样的:

Spring Data Redis 默认使用 JdkSerializationRedisSerializer 作为序列化器。它会将 Java 对象序列化为字节数组存储到 Redis 中。

这就导致了

  • 可读性差:存储在 Redis 中的数据是二进制字节数组,难以直接阅读和理解
  • 内存占用大:比存放的原始数据长度要大很多

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

java 复制代码
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //创建redisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        //配置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //配置JSON序列化工具
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

        //设置key的序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        //设置value的序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }
}

这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:

整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。但这会带来额外的内存开销。

2. StringRedisTemplate

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

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

为了减少内存的消耗,我们可以采用手动序列化的方式,换句话说,就是不借助默认的序列化器,而是我们Java程序员自己来控制序列化的动作,同时,我们只采用String的序列化器,这样,在存储value时,我们就在内存中就不用多存储数据了,从而节约我们的内存空间。

这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式。

省去了我们自定义RedisTemplate的序列化方式的步骤,而是直接使用:

java 复制代码
@SpringBootTest
public class RedisStringTests {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void test() {
        stringRedisTemplate.opsForValue().set("name", "zhangsan");
        System.out.println(stringRedisTemplate.opsForValue().get("name"));
    }
    //ObjectMapper使用前需要引入jackson-databind依赖包
    private static final ObjectMapper mapper = new ObjectMapper();
    @Test
    public  void testSaveUser() throws JsonProcessingException {
        User user = new User("李四", 20);

        String json = mapper.writeValueAsString(user);
        //写入数据
        stringRedisTemplate.opsForValue().set("user",json);
        //读取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user");
        User user1 = mapper.readValue(jsonUser, User.class);
        System.out.println(user1);
    }

    @Test
    public  void testSaveUser2(){
        User user = new User("李四", 20);

        //手动序列化
        String jsonStr = JSONUtil.toJsonStr(user);
        //写入数据
        stringRedisTemplate.opsForValue().set("user", jsonStr);
        //读取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user");
        //手动反序列化
        User user1 = JSONUtil.toBean(jsonStr, User.class);
        System.out.println(user1);
    }
}

以上我使用了Jacksonhutool的JSONUtil两种方式。

此时我们再来看一看存储的数据,我们就会发现那个class数据已经不在了,节约了我们的空间~

最后小总结:

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

  • 方案一:

    • 自定义RedisTemplate
    • 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
  • 方案二:

    • 使用StringRedisTemplate
    • 写入Redis时,手动把对象序列化为JSON
    • 读取Redis时,手动把读取到的JSON反序列化为Java对象

    hash结构操作

java 复制代码
@SpringBootTest
class RedisStringTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Test
    void testHash() {
    	//对应redis当中的 key | field | value
        stringRedisTemplate.opsForHash().put("user", "name", "张三");
        stringRedisTemplate.opsForHash().put("user", "age", "18");

		//对应redis当中 HGETALL:获取一个hash类型的key中的所有的field和value
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user");
        System.out.println("entries = " + entries);
    }
}

好啦,redis在java当中的操作我们就简单演示到这里,至于其他api我们在实战篇再去体会和学习~

相关推荐
Magnum Lehar几秒前
vulkan游戏引擎的核心交换链swapchain实现
java·前端·游戏引擎
半青年13 分钟前
IEC61850规约客户端软件开发实战(第二章)
java·c++·qt·网络协议·c#·信息与通信·iec61850
zzj_26261024 分钟前
头歌java课程实验(学习-Java字符串之正则表达式之元字符之判断字符串是否符合规则)
java·学习·正则表达式
_extraordinary_44 分钟前
Java 异常
java·开发语言
会飞的架狗师1 小时前
【SpringBoot实战】优雅关闭服务
java·spring boot·后端
无处不在的海贼1 小时前
小明的Java面试奇遇之:支付平台高并发交易系统设计与优化[特殊字符]
java·开发语言·面试
居居飒1 小时前
深入理解 JDK、JRE 和 JVM 的区别
java·开发语言·jvm
Bro_cat1 小时前
JVM 核心组件深度解析:堆、方法区、执行引擎与本地方法接口
java·jvm
椰椰椰耶1 小时前
[网页五子棋][匹配模块]前后端交互接口(消息推送机制)、客户端开发(匹配页面、匹配功能)
java·spring boot·json·交互·html5·web
梁小呆瓜1 小时前
掌握Jackson的灵活扩展:@JsonAnyGetter与@JsonAnySetter详解
java·spring boot·json