Working with Objects through RedisTemplate
大多数用户都可能使用 RedisTemplate
及其相应的包 org.springframework.data.redis.core
或其响应式变体 ReactiveRedisTemplate
。模板实际上是 Redis 模块的核心类,因为它具有丰富的功能集。模板为 Redis 交互提供了高级抽象。虽然 [Reactive]RedisConnection
提供了接受和返回二进制值(byte
数组)的底层方法,但模板负责序列化和连接管理,从而使用户不必处理此类细节。
Most users are likely to use RedisTemplate
and its corresponding package, org.springframework.data.redis.core
or its reactive variant ReactiveRedisTemplate
.
The template is, in fact, the central class of the Redis module, due to its rich feature set.
The template offers a high-level abstraction for Redis interactions.
While [Reactive]RedisConnection
offers low-level methods that accept and return binary values (byte
arrays), the template takes care of serialization and connection management, freeing the user from dealing with such details.
RedisTemplate
类实现了 RedisOperations
接口,其响应变体 ReactiveRedisTemplate
实现了 ReactiveRedisOperations
。
The RedisTemplate
class implements the RedisOperations
interface and its reactive variant ReactiveRedisTemplate
implements ReactiveRedisOperations
.
通过“ |
The preferred way to reference operations on a |
此外,模板提供了操作视图(遵循 Redis 命令 reference 中的分组),为针对特定类型或特定键(通过 KeyBound
接口)工作提供了丰富的泛化接口,如下表所示:
Moreover, the template provides operations views (following the grouping from the Redis command reference) that offer rich, generified interfaces for working against a certain type or certain key (through the KeyBound
interfaces) as described in the following table:
.Operational views
- Imperative
-
Interface Description Key Type Operations
GeoOperations
Redis geospatial operations, such as
GEOADD
,GEORADIUS
,…HashOperations
Redis hash operations
HyperLogLogOperations
Redis HyperLogLog operations, such as
PFADD
,PFCOUNT
,…ListOperations
Redis list operations
SetOperations
Redis set operations
ValueOperations
Redis string (or value) operations
ZSetOperations
Redis zset (or sorted set) operations
Key Bound Operations
BoundGeoOperations
Redis key bound geospatial operations
BoundHashOperations
Redis hash key bound operations
BoundKeyOperations
Redis key bound operations
BoundListOperations
Redis list key bound operations
BoundSetOperations
Redis set key bound operations
BoundValueOperations
Redis string (or value) key bound operations
BoundZSetOperations
Redis zset (or sorted set) key bound operations
- Reactive
-
Interface Description Key Type Operations
ReactiveGeoOperations
Redis geospatial operations such as
GEOADD
,GEORADIUS
, and others)ReactiveHashOperations
Redis hash operations
ReactiveHyperLogLogOperations
Redis HyperLogLog operations such as (
PFADD
,PFCOUNT
, and others)ReactiveListOperations
Redis list operations
ReactiveSetOperations
Redis set operations
ReactiveValueOperations
Redis string (or value) operations
ReactiveZSetOperations
一旦配置,模板就是线程安全的,可以在多个实例中重用。
Once configured, the template is thread-safe and can be reused across multiple instances.
RedisTemplate
在其大多数操作中使用基于 Java 的序列化器。这意味着由模板编写的或读取的任何对象都将通过 Java 进行序列化和反序列化。
RedisTemplate
uses a Java-based serializer for most of its operations.
This means that any object written or read by the template is serialized and deserialized through Java.
你可以在模板上更改序列化机制,Redis 模块提供了几种实现,这些实现可在 org.springframework.data.redis.serializer
包中找到。有关更多信息,请参阅 redis:serializer。还可以将任何序列化器设置为 null,并通过将 enableDefaultSerializer
属性设置为 false
来使用原始字节数组的 RedisTemplate
。请注意,模板要求所有键都不能为空。但是,只要底层序列化器接受,值就可以为空。阅读每个序列化器 的 Javadoc 以了解更多信息。
You can change the serialization mechanism on the template, and the Redis module offers several implementations, which are available in the org.springframework.data.redis.serializer
package.
See redis:serializer for more information.
You can also set any of the serializers to null and use RedisTemplate with raw byte arrays by setting the enableDefaultSerializer
property to false
.
Note that the template requires all keys to be non-null.
However, values can be null as long as the underlying serializer accepts them.
Read the Javadoc of each serializer for more information.
对于需要特定模板视图的情况,将视图声明为依赖项并注入模板。容器会自动执行转换,消除 opsFor[X]
调用,如下面的示例所示:
For cases where you need a certain template view, declare the view as a dependency and inject the template.
The container automatically performs the conversion, eliminating the opsFor[X]
calls, as shown in the following example:
-
Java Imperative
-
Java Reactive
-
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(ReactoveRedisConnectionFactory 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
-
Imperative
-
Reactive
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());
}
}
String-focused Convenience Classes
由于 Redis 中存储的键和值通常是 java.lang.String
,因此 Redis 模块为 RedisConnection
和 RedisTemplate
分别提供了两个扩展,即 StringRedisConnection
(及其 DefaultStringRedisConnection
实现)和 StringRedisTemplate
,作为针对复杂字符串操作的便捷一站式解决方案。除了绑定到 String
键之外,模板和连接在下面使用 StringRedisSerializer
,这意味着存储的键和值都是人类可读的(假设 Redis 和代码中都使用了相同的编码)。以下清单显示了一个示例:
Since it is quite common for the keys and values stored in Redis to be java.lang.String
, the Redis modules provides two extensions to RedisConnection
and RedisTemplate
, respectively the StringRedisConnection
(and its DefaultStringRedisConnection
implementation) and StringRedisTemplate
as a convenient one-stop solution for intensive String operations.
In addition to being bound to String
keys, the template and the connection use the StringRedisSerializer
underneath, which means the stored keys and values are human-readable (assuming the same encoding is used both in Redis and your code).
The following listings show an example:
-
Java Imperative
-
Java Reactive
-
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>
-
Imperative
-
Reactive
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 模板一样,RedisTemplate
和 StringRedisTemplate
允许你通过 RedisCallback
接口直接与 Redis 通信。此功能为你提供了完全控制,因为它直接与 RedisConnection
通信。请注意,当使用 StringRedisTemplate
时,回调会收到 StringRedisConnection
的实例。以下示例演示如何使用 RedisCallback
接口:
As with the other Spring templates, RedisTemplate
and StringRedisTemplate
let you talk directly to Redis through the RedisCallback
interface.
This feature gives complete control to you, as it talks directly to the RedisConnection
.
Note that the callback receives an instance of StringRedisConnection
when a StringRedisTemplate
is used.
The following example shows how to use the RedisCallback
interface:
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");
}
});
}
Serializers
从框架的角度来看,Redis 中存储的数据只是字节。虽然 Redis 本身支持各种类型,但大多数情况下,这些类型指代的是数据的存储方式,而不是它表示的内容。用户要自己决定是将信息转换为字符串还是其他任何对象。
From the framework perspective, the data stored in Redis is only bytes. While Redis itself supports various types, for the most part, these refer to the way the data is stored rather than what it represents. It is up to the user to decide whether the information gets translated into strings or any other objects.
在 Spring Data 中,用户(自定义)类型和原始数据(反之亦然)之间的转换由 Spring Data Redis 在 org.springframework.data.redis.serializer
包中处理。
In Spring Data, the conversion between the user (custom) types and raw data (and vice-versa) is handled by Spring Data Redis in the org.springframework.data.redis.serializer
package.
此包包含两种类型的序列化器,顾名思义,这些序列化器负责序列化过程:
This package contains two types of serializers that, as the name implies, take care of the serialization process:
-
Two-way serializers based on
RedisSerializer
. -
Element readers and writers that use
RedisElementReader
andRedisElementWriter
.
这些变体之间的主要区别在于 RedisSerializer
主要序列化为 byte[]
,而读取器和写入器使用 ByteBuffer
。
The main difference between these variants is that RedisSerializer
primarily serializes to byte[]
while readers and writers use ByteBuffer
.
有多种实现可用(包括本文档中已提及的两种):
Multiple implementations are available (including two that have been already mentioned in this documentation):
-
JdkSerializationRedisSerializer
, which is used by default forRedisCache
andRedisTemplate
. -
the
StringRedisSerializer
.
但是,可以使用 OxmSerializer
进行对象/XML 映射,可以通过 Spring {spring-framework-docs}/data-access.html#oxm[OXM] 支持或使用 Jackson2JsonRedisSerializer
或 GenericJackson2JsonRedisSerializer
以 JSON 格式存储数据。
However, one can use OxmSerializer
for Object/XML mapping through Spring {spring-framework-docs}/data-access.html#oxm[OXM] support or Jackson2JsonRedisSerializer
or GenericJackson2JsonRedisSerializer
for storing data in JSON format.
请注意,存储格式不限于值。它可以毫无限制地用于键、值或哈希。
Do note that the storage format is not limited only to values. It can be used for keys, values, or hashes without any restrictions.
默认情况下,RedisCache
和 RedisTemplate
被配置为使用 Java 本机序列化。Java 本机序列化允许运行远程代码,原因是注入未经验证的字节代码的有效负载会利用易受攻击的库和类。处理输入时,可能会导致在反序列化步骤中在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(例如 JSON)。
By default, RedisCache
and RedisTemplate
are configured to use Java native serialization.
Java native serialization is known for allowing the running of remote code caused by payloads that exploit vulnerable libraries and classes injecting unverified bytecode.
Manipulated input could lead to unwanted code being run in the application during the deserialization step.
As a consequence, do not use serialization in untrusted environments.
In general, we strongly recommend any other message format (such as JSON) instead.
如果您担心由于 Java 序列化而引起的安全性漏洞,请考虑核心 JVM 级别的一般用途序列化过滤机制:
If you are concerned about security vulnerabilities due to Java serialization, consider the general-purpose serialization filter mechanism at the core JVM level: