迁移指南
本节包含有关迁移步骤、弃用和移除的详细信息。
从 3.x 升级到 4.x
先升级到最新的 Spring Data Redis 3.5.x 版本,并在迁移到 4.0 之前替换为移除而弃用的 API。
Jackson 3
Spring Data Redis 4.0 使用 Jackson 3 作为其主要的 JSON 库。下面列出的 Jackson 2 API 已弃用,将在后续版本中移除。
RedisSerializer.json() 现在使用来自 tools.jackson 包的 Jackson 3。它需要 tools.jackson.core:jackson-databind 以及最新版本的 com.fasterxml.jackson.core:jackson-annotations。有关更新应用程序代码的信息,请参阅 Jackson 3 迁移指南。
下表列出了 Jackson 3 的替代方案:
| 用途 | Jackson 2 API | Jackson 3 API |
|---|---|---|
| 通用 JSON 序列化器 | GenericJackson2JsonRedisSerializer | GenericJacksonJsonRedisSerializer |
| 类型化 JSON 序列化器 | Jackson2JsonRedisSerializer | JacksonJsonRedisSerializer |
| Hash 映射器 | Jackson2HashMapper | JacksonHashMapper |
| 自定义读取器和写入器契约 | Jackson2ObjectReader and Jackson2ObjectWriter | JacksonObjectReader and JacksonObjectWriter |
GenericJackson2JsonRedisSerializer 默认启用默认类型,而无需 PolymorphicTypeValidator。GenericJacksonJsonRedisSerializer 默认不启用默认类型。如果你需要默认类型,请通过 GenericJacksonJsonRedisSerializer 构建器启用它(GenericJacksonJsonRedisSerializer.builder().enableDefaultTyping(…))。
如果你在迁移期间继续使用 Jackson 2,请在构造函数和构建器中将 JacksonObjectReader 替换为 Jackson2ObjectReader,将 JacksonObjectWriter 替换为 Jackson2ObjectWriter。
以前,RedisSerializer.json() 使用 GenericJackson2JsonRedisSerializer。Jackson 3 序列化器生成的 JSON 输出可能与 Jackson 2 的输出不同。在现有值迁移完成之前,请继续使用 GenericJackson2JsonRedisSerializer 来读取这些值:
RedisSerializer<Object> serializer = new GenericJackson2JsonRedisSerializer();
使用 jackson2CompatibilityMode() 来读写与 Jackson2HashMapper 兼容的哈希:
JacksonHashMapper mapper = JacksonHashMapper.builder()
.jackson2CompatibilityMode()
.build();
在构建器上选择 flatten() 或 hierarchical(),以匹配现有的哈希表示形式。
Redis 缓存
RedisCacheWriter 扩展了 evict(…) 和 clear(…) 方法,以支持异步缓存逐出和清除。
如果配置的 RedisConnectionFactory 实现了 ReactiveRedisConnectionFactory,则默认的 RedisCacheWriter 对 put(…)、evict(…) 和 clear(…) 使用异步行为。这些操作可能在调用方法返回之后才完成。对 Cache.evictIfPresent(…) 或 Cache.invalidate(…) 的调用会强制同步行为,即在返回之前等待操作完成。要对所有操作使用同步行为,请在 RedisCacheWriter 构建器上调用 immediateWrites():
RedisCacheWriter cacheWriter = RedisCacheWriter.create(connectionFactory,
configurer -> configurer.immediateWrites());
表 1. 缓存 API 变更
| 3.x API | 4.x 替代方案 |
|---|---|
RedisCacheConfiguration.getTtl() | RedisCacheConfiguration.getTtlFunction().getTimeToLive(key, value) |
RedisCacheManager(RedisCacheWriter, RedisCacheConfiguration, Map, boolean) | RedisCacheManager(RedisCacheWriter, RedisCacheConfiguration, boolean, Map) |
StringRedisTemplate 连接回调
StringRedisTemplate 不再将传递给回调的连接暴露为 StringRedisConnection。请改用 StringRedisTemplate 操作:
String value = stringRedisTemplate.opsForValue().get("key");
对于其余回调,请使用二进制的 RedisConnection API。
Lettuce 可观测性
Spring Data Redis 4.0 移除了其 Lettuce 可观测性适配器,转而使用 Lettuce 原生的 Micrometer 集成。请使用 Lettuce 的 io.lettuce.core.tracing.LettuceObservationContext 代替被移除的 org.springframework.data.redis.connection.lettuce.observability.LettuceObservationContext。RedisObservation 没有公开的替代方案。请用 Lettuce 的 io.lettuce.core.tracing.MicrometerTracing 替换 MicrometerTracingAdapter:
MicrometerTracing tracing = new MicrometerTracing(observationRegistry, "Redis");
ClientResources clientResources = ClientResources.builder()
.tracing(tracing)
.build();
在 LettuceClientConfiguration 上配置生成的 ClientResources 实例。有关高级配置选项,请参阅 Lettuce 的 Micrometer Tracing 文档。
JSpecify 可空性
Spring Data Redis 4.0 使用 JSpecify 可空性注解来指示 API 的空性。大多数包默认标记为可空。某些包和接口无法声明非空默认值,因为返回值取决于连接状态。在事务执行期间或管道传输期间调用的方法会返回 null,直到事务被执行或管道被关闭。受影响的类型使用 @NullUnmarked,并对保留非空契约的参数和返回值应用 @NonNull。
RedisSerializer.serialize(Object) 现在必须返回非空字节数组。自定义 RedisSerializer 实现可以对 null 值使用空字节数组。RedisSerializer.deserialize(byte[]) 仍可返回 null。有关详细信息,请参阅 Spring Framework 关于空安全的文档。
其他已移除和已变更的 API
表 2. 配置、操作和实用工具
| 3.x API | 4.x 替代方案或操作 |
|---|---|
new RedisClusterConfiguration(PropertySource) | RedisClusterConfiguration.of(PropertySource) |
new RedisSentinelConfiguration(PropertySource) | RedisSentinelConfiguration.of(PropertySource) |
BoundSetOperations.diff(…) | BoundSetOperations.difference(…) |
接受 RedisZSetCommands.Range 的 BoundZSetOperations、ZSetOperations 和 RedisZSet 重载 | 使用接受 org.springframework.data.domain.Range<String> 的重载。 |
RedisPersistentEntity.hasExplictTimeToLiveProperty() | RedisPersistentEntity.hasExplicitTimeToLiveProperty() |
返回 Boolean 的 Converters.toBoolean(Long) | 重新编译调用方。该方法现在返回原始类型 boolean。 |
返回 Long 的 Converters.toTimeMillis(…) | 重新编译调用方。这些方法现在返回原始类型 long。 |
LettuceConverters.toBytesList(Collection<byte[]>) | 直接使用输入集合,或者在需要时将其转换为 List。 |
ByteUtils.extractBytes(ByteBuffer) | ByteUtils.getBytes(ByteBuffer) |
RedisAssertions | 使用 org.springframework.util.Assert 或显式检查。 |
表 3. 扩展 API
| 3.x API | 4.x 替代方案或操作 |
|---|---|
new ScanIteration(long, Collection) 和 ScanIteration.getCursorId() | 使用 new ScanIteration(Cursor.CursorId, Collection) 和 ScanIteration.getId()。 |
ScanCursor.doOpen(long) 和 ScanCursor.isFinished(long) | 重写接受 Cursor.CursorId 的变体。 |
接受 QueryMethodEvaluationContextProvider 的 RedisPartTreeQuery 构造函数 | 使用接受 ValueExpressionDelegate 的构造函数。 |
JedisClusterTopologyProvider.shouldUseCachedValue() | 重写 shouldUseCachedValue(JedisClusterTopology)。 |
从 2.x 升级到 3.x
重新/已移除的类型
| 类型 | 替代方案 |
|---|---|
| o.s.d.redis.Version | o.s.d.util.Version |
| o.s.d.redis.VersionParser | - |
| o.s.d.redis.connection.RedisZSetCommands.Aggregate | o.s.d.redis.connection.zset.Aggregate |
| o.s.d.redis.connection.RedisZSetCommands.Tuple | o.s.d.redis.connection.zset.Tuple |
| o.s.d.redis.connection.RedisZSetCommands.Weights | o.s.d.redis.connection.zset.Weights |
| o.s.d.redis.connection.RedisZSetCommands.Range | o.s.d.domain.Range |
| o.s.d.redis.connection.RedisZSetCommands.Limit | o.s.d.redis.connection.Limit.java |
| o.s.d.redis.connection.jedis.JedisUtils | - |
| o.s.d.redis.connection.jedis.JedisVersionUtil | - |
| o.s.d.redis.core.convert.CustomConversions | o.s.d.convert.CustomConversions |
已变更的方法和类型
表 4. 核心
| 类型 | 方法 | 替代方案 |
|---|---|---|
| o.s.d.redis.core.Cursor | open | - |
| o.s.d.redis.core.RedisTemplate | execute | doWithKeys |
| o.s.d.redis.stream.StreamMessageListenerContainer | isAutoAck | isAutoAcknowledge |
| o.s.d.redis.stream.StreamMessageListenerContainer | autoAck | autoAcknowledge |
表 5. Redis 连接
| 类型 | 方法 | 替代方案 |
|---|---|---|
| o.s.d.redis.connection.ClusterCommandExecutionFailureException | getCauses | getSuppressed |
| o.s.d.redis.connection.RedisConnection | bgWriteAof | bgReWriteAof |
| o.s.d.redis.connection.RedisConnection | slaveOf | replicaOf |
| o.s.d.redis.connection.RedisConnection | slaveOfNoOne | replicaOfNoOne |
| o.s.d.redis.connection.ReactiveClusterCommands | clusterGetSlaves | clusterGetReplicas |
| o.s.d.redis.connection.ReactiveClusterCommands | clusterGetMasterSlaveMap | clusterGetMasterReplicaMap |
| o.s.d.redis.connection.ReactiveKeyCommands | getNewName | getNewKey |
| o.s.d.redis.connection.RedisClusterNode.Flag | SLAVE | REPLICA |
| o.s.d.redis.connection.RedisClusterNode.Builder | slaveOf | replicaOf |
| o.s.d.redis.connection.RedisNode | isSlave | isReplica |
| o.s.d.redis.connection.RedisSentinelCommands | slaves | replicas |
| o.s.d.redis.connection.RedisServer | getNumberSlaves | getNumberReplicas |
| o.s.d.redis.connection.RedisServerCommands | slaveOf | replicaOf |
| o.s.d.redis.core.ClusterOperations | getSlaves | getReplicas |
| o.s.d.redis.core.RedisOperations | slaveOf | replicaOf |
表 6. Redis 操作
| 类型 | 方法 | 替代方案 |
|---|---|---|
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoAdd | add |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoDist | distance |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoHash | hash |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoPos | position |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoRadius | radius |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoRadiusByMember | radius |
| o.s.d.redis.core.GeoOperations & BoundGeoOperations | geoRemove | remove |
表 7. Redis 缓存
| 类型 | 方法 | 替代方案 |
|---|---|---|
| o.s.d.redis.cache.RedisCacheConfiguration | prefixKeysWith | prefixCacheNameWith |
| o.s.d.redis.cache.RedisCacheConfiguration | getKeyPrefix | getKeyPrefixFor |
Jedis
请阅读 Jedis 的升级指南,其中涵盖了重要的驱动程序变更。
表 8. Jedis Redis 连接
| 类型 | 方法 | 替代方案 |
|---|---|---|
| o.s.d.redis.connection.jedis.JedisConnectionFactory | getShardInfo | 可通过 JedisClientConfiguration 获取 |
| o.s.d.redis.connection.jedis.JedisConnectionFactory | setShardInfo | 可通过 JedisClientConfiguration 设置 |
| o.s.d.redis.connection.jedis.JedisConnectionFactory | createCluster | 现在需要 Connection 而不是 Jedis 实例 |
| o.s.d.redis.connection.jedis.JedisConverters | 现在具有包可见性 | |
| o.s.d.redis.connection.jedis.JedisConverters | tuplesToTuples | - |
| o.s.d.redis.connection.jedis.JedisConverters | tuplesToTuples | - |
| o.s.d.redis.connection.jedis.JedisConverters | stringListToByteList | - |
| o.s.d.redis.connection.jedis.JedisConverters | stringSetToByteSet | - |
| o.s.d.redis.connection.jedis.JedisConverters | stringMapToByteMap | - |
| o.s.d.redis.connection.jedis.JedisConverters | tupleSetToTupleSet | - |
| o.s.d.redis.connection.jedis.JedisConverters | toTupleSet | - |
| o.s.d.redis.connection.jedis.JedisConverters | toDataAccessException | o.s.d.redis.connection.jedis.JedisExceptionConverter#convert |
事务 / 管道
管道和事务现在是互斥的。在管道/事务模式下使用服务器或连接命令不再可行。
Lettuce
Lettuce 连接池
LettucePool 及其实现 DefaultLettucePool 已被移除,且没有替代方案。有关驱动程序原生连接池功能,请参阅驱动程序文档。接受连接池参数的方法已更新。这会影响 LettuceConnectionFactory 和 LettuceConnection 上的方法。
Lettuce 认证
AuthenticatingRedisClient 已被移除,且没有替代方案。请参阅驱动程序文档,了解如何使用 RedisURI 设置认证数据。