使用 RedisTemplate 操作对象

大多数用户可能会使用 RedisTemplate 及其对应的包 org.springframework.data.redis.core,或者其响应式变体 ReactiveRedisTemplate。实际上,由于其丰富的功能集,该模板是 Redis 模块的核心类。该模板为 Redis 交互提供了高级抽象。虽然 [Reactive]RedisConnection 提供了接受并返回二进制值(byte 数组)的低级方法,但该模板负责序列化和连接管理,使用户无需处理这些细节。

RedisTemplate 类实现了 RedisOperations 接口,其响应式变体 ReactiveRedisTemplate 实现了 ReactiveRedisOperations

引用 [Reactive]RedisTemplate 实例上的操作的首选方式是通过 [Reactive]RedisOperations 接口。

此外,该模板提供了操作视图(遵循 Redis 命令参考中的分组),这些视图提供了丰富、泛型化的接口,用于对特定类型或特定键(通过 KeyBound 接口)进行操作,如下表所示

操作视图
  • 命令式

  • 响应式

接口 描述

键类型操作

GeoOperations

Redis 地理空间操作,例如 GEOADDGEORADIUS 等…​

HashOperations

Redis hash 操作

HyperLogLogOperations

Redis HyperLogLog 操作,例如 PFADDPFCOUNT 等…​

ListOperations

Redis 列表操作

SetOperations

Redis set 操作

ValueOperations

Redis string(或 value)操作

ZSetOperations

Redis zset(或有序 set)操作

键绑定操作

BoundGeoOperations

Redis 键绑定地理空间操作

BoundHashOperations

Redis hash 键绑定操作

BoundKeyOperations

Redis 键绑定操作

BoundListOperations

Redis 列表键绑定操作

BoundSetOperations

Redis set 键绑定操作

BoundValueOperations

Redis string(或 value)键绑定操作

BoundZSetOperations

Redis zset(或有序 set)键绑定操作

接口 描述

键类型操作

ReactiveGeoOperations

Redis 地理空间操作(例如 GEOADDGEORADIUS 等)

ReactiveHashOperations

Redis hash 操作

ReactiveHyperLogLogOperations

Redis HyperLogLog 操作(例如 PFADDPFCOUNT 等)

ReactiveListOperations

Redis 列表操作

ReactiveSetOperations

Redis set 操作

ReactiveValueOperations

Redis string(或 value)操作

ReactiveZSetOperations

Redis zset(或有序 set)操作

一旦配置完成,该模板是线程安全的,可以在多个实例中重复使用。

RedisTemplate 对其大多数操作使用基于 Java 的序列化器。这意味着通过该模板写入或读取的任何对象都通过 Java 进行序列化和反序列化。

您可以更改模板上的序列化机制,Redis 模块提供了多种实现,这些实现位于 org.springframework.data.redis.serializer 包中。有关更多信息,请参阅序列化器。您还可以将任何序列化器设置为 null,并通过将 enableDefaultSerializer 属性设置为 false 来使用带有原始字节数组的 RedisTemplate。请注意,该模板要求所有键非 null。但是,只要底层序列化器接受,值可以为 null。阅读每个序列化器的 Javadoc 以获取更多信息。

对于需要特定模板视图的情况,请将该视图声明为依赖项并注入模板。容器会自动执行转换,从而省去了 opsFor[X] 调用,如下例所示

配置模板 API
  • Java 命令式

  • Java 响应式

  • XML

@Configuration
class MyConfig {

  @Bean
  LettuceConnectionFactory connectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {

    RedisTemplate<String, String> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);
    return template;
  }
}
@Configuration
class MyConfig {

  @Bean
  LettuceConnectionFactory connectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  ReactiveRedisTemplate<String, String> ReactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory) {
    return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
  <!-- redis template definition -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="redisConnectionFactory"/>
  ...

</beans>
使用 [Reactive]RedisTemplate 将项推入列表
  • 命令式

  • 响应式

public class Example {

  // inject the actual operations
  @Autowired
  private RedisOperations<String, String> operations;

  // inject the template as ListOperations
  @Resource(name="redisTemplate")
  private ListOperations<String, String> listOps;

  public void addLink(String userId, URL url) {
    listOps.leftPush(userId, url.toExternalForm());
  }
}
public class Example {

  // inject the actual template
  @Autowired
  private ReactiveRedisOperations<String, String> operations;

  public Mono<Long> addLink(String userId, URL url) {
    return operations.opsForList().leftPush(userId, url.toExternalForm());
  }
}

字符串重点的便利类

由于存储在 Redis 中的键和值通常是 java.lang.String,Redis 模块为 RedisConnectionRedisTemplate 分别提供了两个扩展:StringRedisConnection(及其 DefaultStringRedisConnection 实现)和 StringRedisTemplate,作为密集型字符串操作的便捷一站式解决方案。除了绑定到 String 键外,该模板和连接在底层使用 StringRedisSerializer,这意味着存储的键和值是人类可读的(假设 Redis 和您的代码中使用相同的编码)。以下列表显示了一个示例

  • Java 命令式

  • Java 响应式

  • XML

@Configuration
class RedisConfiguration {

  @Bean
  LettuceConnectionFactory redisConnectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }
}
@Configuration
class RedisConfiguration {

  @Bean
  LettuceConnectionFactory redisConnectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  ReactiveStringRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
    return new ReactiveStringRedisTemplate<>(factory);
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>

  <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="redisConnectionFactory"/>

</beans>
  • 命令式

  • 响应式

public class Example {

  @Autowired
  private StringRedisTemplate redisTemplate;

  public void addLink(String userId, URL url) {
    redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}
public class Example {

  @Autowired
  private ReactiveStringRedisTemplate redisTemplate;

  public Mono<Long> addLink(String userId, URL url) {
    return redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}

与其他的 Spring 模板一样,RedisTemplateStringRedisTemplate 允许您通过 RedisCallback 接口直接与 Redis 通信。此功能为您提供了完全控制权,因为它直接与 RedisConnection 通信。请注意,使用 StringRedisTemplate 时,回调会接收 StringRedisConnection 的实例。以下示例显示了如何使用 RedisCallback 接口

public void useCallback() {

  redisOperations.execute(new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
      Long size = connection.dbSize();
      // Can cast to StringRedisConnection if using a StringRedisTemplate
      ((StringRedisConnection)connection).set("key", "value");
    }
   });
}

序列化器

从框架的角度来看,存储在 Redis 中的数据只是字节。虽然 Redis 本身支持各种类型,但大多数情况下,这些类型指的是数据的存储方式,而不是数据代表的含义。用户需要决定是将信息翻译成字符串还是任何其他对象。

在 Spring Data 中,用户(自定义)类型与原始数据之间的转换(反之亦然)由 Spring Data Redis 在 org.springframework.data.redis.serializer 包中处理。

该包包含两种类型的序列化器,顾名思义,它们负责序列化过程

  • 基于 RedisSerializer 的双向序列化器。

  • 使用 RedisElementReaderRedisElementWriter 的元素读取器和写入器。

这些变体之间的主要区别在于 RedisSerializer 主要序列化为 byte[],而读取器和写入器使用 ByteBuffer

提供了多种实现(包括本文档中已经提到的两种)

但是,可以使用 OxmSerializer 通过 Spring OXM 支持进行对象/XML 映射,或者使用 Jackson2JsonRedisSerializerGenericJackson2JsonRedisSerializerJSON 格式存储数据。

请注意,存储格式不仅限于值。它可以无限制地用于键、值或 hash。

默认情况下,RedisCacheRedisTemplate 配置为使用 Java 原生序列化。Java 原生序列化已知会因利用漏洞库和类注入未经验证的字节码的有效载荷而导致远程代码执行。恶意输入可能导致在反序列化步骤期间在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(例如 JSON)代替。

如果您担心 Java 序列化引起的安全漏洞,请考虑核心 JVM 级别的通用序列化过滤器机制