Spring Data Redis

Redis是一个基于Key-Value形式的非关系型内存数据库,主要用作高性能缓存和存储一些临时信息。Java程序中操作Redis数据库有Jedis、Redisson、Lettuce等客户端可以直接使用,而在使用Spring框架时,Spring Data Redis项目提供了RedisTemplate,它为我们进一步封装了Redis客户端,Jedis、Redisson等客户端库都支持集成Spring Data Redis,因此使用Spring Data Redis我们可以在这些客户端之间无缝切换,Spring生态下的很多库也都依赖Spring Data Redis,使用它能起到增强程序代码可移植性的目的。

引入Maven依赖

对于传统Spring工程

对于非SpringBoot工程,引入Spring Data Redis有点复杂,我们要考虑引入Maven依赖的版本兼容性问题。Spring Data Redis中,1.x和2.x有不兼容的API,这里我们使用2.x版本。

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.7.0</version>
</dependency>

Lettuce、Jedis等客户端都能够很方便的集成到Spring中,这里我们选择Lettuce。

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.1.8.RELEASE</version>
</dependency>

存取对象时Spring Data Redis默认用了Java的序列化机制,但如果需要存储的文本有一定的可读性,对象序列化建议改为JSON方式,Spring Data Redis内置支持Jackson序列化器。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.13.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.13.3</version>
</dependency>

对于SpringBoot工程

如果是SpringBoot环境,集成Spring Data Redis只需要引入一个起步依赖即可。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件

在非SpringBoot环境下,使用RedisTemplate前我们需要在Spring配置文件中配置相关的Bean。RedisTemplate需要通过一个RedisConnectionFactory对象配置,支持该对象的Redis客户端都可以配置为RedisTemplate的底层客户端。在最新版本中,官方推荐使用Lettuce作为客户端。

applicationContext.xml

<!-- 配置Lettuce客户端 -->
<bean id="lettuceConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
    <property name="hostName" value="127.0.0.1" />
    <property name="port" value="6379" />
</bean>
<!-- 配置Spring Data Redis -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="lettuceConnectionFactory" />
</bean>

SpringBoot环境下就非常简单了,我们只需要一些简洁的配置,例子如下。

application.properties

spring.redis.host=127.0.0.1
spring.redis.port=6379

Lettuce客户端还有很多其他参数,比如连接的数据库序号、密码等,以及集群模式支持,具体可以参考Lettuce相关章节。

RedisTemplate简单使用

下面例子代码我们使用Spring Data Redis存取一个字符串数据。

Main.java

package com.gacfox.demoredis;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取RedisTemplate的Bean
        RedisTemplate<String, String> redisTemplate = (RedisTemplate<String, String>) context.getBean("redisTemplate");
        // 获取ValueOperations操作对象
        ValueOperations<String, String> vops = redisTemplate.opsForValue();
        // 向Redis写入值
        vops.set("str", "hello, world!");
        // 从Redis获取值
        String s = vops.get("str");

        System.out.println(s);
    }
}

代码非常简单,我们从Spring的ApplicationContext中获得我们之前XML中配置好的bean,RedisTemplate中有一组方法opsFor*专门用于操作Redis的各种数据结构,我们获取*Operations对象调用其中的方法即可。

注意:上面代码我们直接从Spring应用上下文中获取了redisTemplate对象,实际使用中,我们一般都是通过依赖注入的方式使用。

自定义类型的Redis存取

上面例子中我们可以看到RedisTemplate是支持泛型的,下面代码演示实例化一个自定义的Java对象,存入Redis再取出。

package com.gacfox.demoredis;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        RedisTemplate<String, Student> redisTemplate = (RedisTemplate<String, Student>) context.getBean("redisTemplate");

        Student s = new Student();
        s.setName("Alice");
        s.setAge(18);

        ValueOperations<String, Student> vops = redisTemplate.opsForValue();
        vops.set("student", s);
        vops.get("student");
    }
}

这里要注意的是,我们必须为要存储的类实现Serializable接口,这样该对象才能够成功进行序列化并存入Redis数据库中,在Redis中序列化后的对象使用string类型进行存储。除此之外,一个可序列化对象引用其他多个可序列化对象,也是能够成功存入Redis中的,总之只要能够成功进行Java对象序列化,就能存入Redis中。

序列化器配置

Spring Data Redis默认使用Java自带的对象序列化机制,之前例子即使我们存储的只是一个简单的String类型,但是实际上存入Redis中的内容可能和我们想象的不太相同。

vops.set("str", "hello, world!");

Redis中实际的存储结果并不是键值对"str""hello, world!",我们可以在redis-cli中使用keys *进行查询,得到的键大概是这样的。

"\xac\xed\x00\x05t\x00\x03str"

再查询键对应的值,结果可能如下。

127.0.0.1:6379> get "\xac\xed\x00\x05t\x00\x03str"
"\xac\xed\x00\x05t\x00\rhello, world!"

这是因为Spring Data Redis底层默认使用JDK的序列化机制,包括String类型也会采用这种序列化机制。JDK序列化的优点是性能较好,但如果为了存取的数据具有更好的可读性,我们可以为RedisTemplate手动指定JSON类型的序列化器。

对于普通传统Spring工程,我们可以按如下配置RedisTemplate这个Bean,对于SpringBoot工程我们替换为等效的JavaConfig即可。

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="lettuceConnectionFactory" />
    <property name="keySerializer">
        <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
    </property>
    <property name="valueSerializer">
        <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
    </property>
    <property name="hashKeySerializer">
        <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
    </property>
    <property name="hashValueSerializer">
        <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
    </property>
</bean>

GenericJackson2JsonRedisSerializer是支持类型的JSON序列化器,其输出例子如下。

{
  "@class": "com.gacfox.demoredis.Student",
  "name": "Alice",
  "age": 18
}

自动生成的@class键指定了JSON对象节点需要反序列化的Java类型。除了GenericJackson2JsonRedisSerializer,Spring Data Redis还有一个Jackson2JsonRedisSerializer比较常用,它存储的就是JSON纯文本,对象一旦存入后,就只能手动以字符串形式取出,并手动调用JSON反序列化器得到对象。

有关其他Redis数据类型的操作

Redis提供了5种灵活的数据结构供我们使用,在RedisTemplate中都能够找到对应的操作方法:

opsForValue():存取字符串(配置序列化器后,存取Java对象会自动序列化和反序列化为字符串)

opsForHash():存取哈希对象

opsForList():存取列表

opsForSet():存取集合对象

OpsForZSet():存取有序集合对象

从日常开发角度来看,前两种是最为常用的。这些内容都比较简单,这里就不赘述了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。