对于最新的稳定版本,请使用 Spring Data Redis 3.5.3spring-doc.cadn.net.cn

Redis 缓存

Spring Data Redis org.springframework.data.redis.cache包。 要使用 Redis 作为支持实现,请添加RedisCacheManager到您的配置,如下所示:spring-doc.cadn.net.cn

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
    return RedisCacheManager.create(connectionFactory);
}

RedisCacheManager行为可以配置为RedisCacheManager.RedisCacheManagerBuilder,允许您设置默认值RedisCacheManager、事务行为和预定义缓存。spring-doc.cadn.net.cn

RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
    .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
    .transactionAware()
    .withInitialCacheConfigurations(Collections.singletonMap("predefined",
        RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()))
    .build();

如前面的示例所示,RedisCacheManager允许基于每个缓存进行自定义配置。spring-doc.cadn.net.cn

的行为RedisCache创建者RedisCacheManager定义为RedisCacheConfiguration. 通过配置,您可以设置密钥到期时间、前缀和RedisSerializer用于在二进制存储格式之间进行转换的实现,如以下示例所示:spring-doc.cadn.net.cn

RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
    .entryTtl(Duration.ofSeconds(1))
    .disableCachingNullValues();

RedisCacheManager默认为无锁RedisCacheWriter用于读取和写入二进制值。 无锁缓存可提高吞吐量。 缺少条目锁定可能会导致Cache putIfAbsentclean作,因为这些作需要将多个命令发送到 Redis。 锁定对应项通过设置显式锁定键并检查是否存在该键来防止命令重叠,这会导致额外的请求和潜在的命令等待时间。spring-doc.cadn.net.cn

锁定适用于缓存级别,而不是每个缓存条目spring-doc.cadn.net.cn

可以选择加入锁定行为,如下所示:spring-doc.cadn.net.cn

RedisCacheManager cacheManager = RedisCacheManager
    .builder(RedisCacheWriter.lockingRedisCacheWriter(connectionFactory))
    .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
    ...

默认情况下,任何key对于缓存条目,以实际缓存名称为前缀,后跟两个冒号(::). 此行为可以更改为静态前缀和计算前缀。spring-doc.cadn.net.cn

以下示例演示如何设置静态前缀:spring-doc.cadn.net.cn

// static key prefix
RedisCacheConfiguration.defaultCacheConfig().prefixCacheNameWith("(͡° ᴥ ͡°)");

The following example shows how to set a computed prefix:

// computed key prefix
RedisCacheConfiguration.defaultCacheConfig()
    .computePrefixWith(cacheName -> "¯\_(ツ)_/¯" + cacheName);

缓存实现默认使用KEYSDEL以清除缓存。KEYS可能会导致大型关键空间的性能问题。 因此,默认的RedisCacheWriter可以使用BatchStrategy切换到SCAN基于批处理策略。 这SCAN策略需要批量大小以避免过多的 Redis 命令往返:spring-doc.cadn.net.cn

RedisCacheManager cacheManager = RedisCacheManager
    .builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, BatchStrategies.scan(1000)))
    .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
    ...

KEYS使用任何驱动程序和 Redis作模式(独立、群集)完全支持批处理策略。SCAN在使用 Lettuce 驱动程序时完全支持。 绝地支持SCAN仅在非聚类模式下。spring-doc.cadn.net.cn

下表列出了RedisCacheManager:spring-doc.cadn.net.cn

表 1.RedisCacheManager默认值
设置

缓存写入器spring-doc.cadn.net.cn

非锁死 /KEYS批量策略spring-doc.cadn.net.cn

缓存配置spring-doc.cadn.net.cn

RedisCacheConfiguration#defaultConfigurationspring-doc.cadn.net.cn

初始缓存spring-doc.cadn.net.cn

没有spring-doc.cadn.net.cn

事务感知spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

下表列出了RedisCacheConfiguration:spring-doc.cadn.net.cn

表 2.RedisCacheConfiguration 默认值
密钥过期 没有

缓存nullspring-doc.cadn.net.cn

是的spring-doc.cadn.net.cn

前缀键spring-doc.cadn.net.cn

是的spring-doc.cadn.net.cn

默认前缀spring-doc.cadn.net.cn

实际缓存名称spring-doc.cadn.net.cn

密钥序列化器spring-doc.cadn.net.cn

StringRedisSerializerspring-doc.cadn.net.cn

值序列化器spring-doc.cadn.net.cn

JdkSerializationRedisSerializerspring-doc.cadn.net.cn

转换服务spring-doc.cadn.net.cn

DefaultFormattingConversionService使用默认缓存密钥转换器spring-doc.cadn.net.cn

默认情况下RedisCache,则禁用统计信息。 用RedisCacheManagerBuilder.enableStatistics()通过收集本地命中未命中RedisCache#getStatistics(),返回收集数据的快照。spring-doc.cadn.net.cn

Redis 缓存过期

空闲时间 (TTI) 和生存时间 (TTL) 的实现在定义和行为上也有所不同,即使在不同的数据存储中也是如此。spring-doc.cadn.net.cn

  • 生存时间 (TTL) 过期 - TTL 仅通过创建或更新数据访问作进行设置和重置。 只要条目是在 TTL 过期超时之前写入的,包括在创建时,条目的超时就会重置为配置的 TTL 过期超时持续时间。 例如,如果 TTL 过期超时设置为 5 分钟,则超时将在条目创建时设置为 5 分钟,并在此后和 5 分钟间隔到期之前更新条目时重置为 5 分钟。 如果 5 分钟内没有发生更新,即使条目被读取了多次,甚至在 5 分钟间隔内只读取了一次,该条目仍将过期。 在声明 TTL 到期策略时,必须编写条目以防止条目过期。spring-doc.cadn.net.cn

  • 空闲时间 (TTI) 过期 - 每当读取条目以及条目更新时,都会重置 TTI,并且是 TTL 过期策略的有效扩展。spring-doc.cadn.net.cn

某些数据存储在配置 TTL 时使条目过期,无论该条目上发生哪种类型的数据访问作(读取、写入或其他)。 在设置的配置的 TTL 过期超时后,无论如何,该条目都会从数据存储中逐出。 逐出作(例如:销毁、失效、溢出到磁盘(对于持久性存储)等)是特定于数据存储的。spring-doc.cadn.net.cn

生存时间 (TTL) 到期

Spring Data Redis 的Cache实现支持缓存条目的生存时间 (TTL) 过期。 用户可以将 TTL 过期超时配置为固定Duration或动态计算的Duration每个缓存条目通过提供新的RedisCacheWriter.TtlFunction接口。spring-doc.cadn.net.cn

RedisCacheWriter.TtlFunctionSpring Data Redis 中引入的接口3.2.0.spring-doc.cadn.net.cn

如果所有缓存条目都应在设定的时间后过期,则只需配置一个 TTL 过期超时,并使用Duration如下:spring-doc.cadn.net.cn

RedisCacheConfiguration fiveMinuteTtlExpirationDefaults =
    RedisCacheConfiguration.defaultCacheConfig().enableTtl(Duration.ofMinutes(5));

但是,如果 TTL 过期超时因缓存条目而异,则必须提供RedisCacheWriter.TtlFunction接口:spring-doc.cadn.net.cn

enum MyCustomTtlFunction implements TtlFunction {

    INSTANCE;

    @Override
    public Duration getTimeToLive(Object key, @Nullable Object value) {
        // compute a TTL expiration timeout (Duration) based on the cache entry key and/or value
    }
}

在引擎盖下,一个固定的DurationTTL 过期包装在TtlFunction返回提供的Duration.spring-doc.cadn.net.cn

然后,您可以配置固定的Duration或动态的、每个缓存条目Duration使用以下方法在全球范围内进行 TTL 过期:spring-doc.cadn.net.cn

全局固定持续时间 TTL 过期超时
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
    .cacheDefaults(fiveMinuteTtlExpirationDefaults)
    .build();

或者,或者:spring-doc.cadn.net.cn

全局动态计算的每个缓存条目持续时间 TTL 过期超时
RedisCacheConfiguration defaults = RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(MyCustomTtlFunction.INSTANCE);

RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
    .cacheDefaults(defaults)
    .build();

当然,您可以使用以下方法组合全局配置和每个缓存配置:spring-doc.cadn.net.cn

全局固定持续时间 TTL 过期超时
RedisCacheConfiguration predefined = RedisCacheConfiguration.defaultCacheConfig()
                                         .entryTtl(MyCustomTtlFunction.INSTANCE);

Map<String, RedisCacheConfiguration> initialCaches = Collections.singletonMap("predefined", predefined);

RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
    .cacheDefaults(fiveMinuteTtlExpirationDefaults)
    .withInitialCacheConfigurations(initialCaches)
    .build();

空闲时间 (TTI) 到期

Redis 本身不支持真正的空闲时间 (TTI) 过期的概念。 尽管如此,使用 Spring Data Redis 的 Cache 实现,还是可以实现类似空闲时间 (TTI) 过期的行为。spring-doc.cadn.net.cn

Spring Data Redis 的 Cache 实现中 TTI 的配置必须显式启用,即选择加入。 此外,您还必须使用固定的DurationTtlFunction接口,如上文 Redis 缓存过期中所述。spring-doc.cadn.net.cn

@Configuration
@EnableCaching
class RedisConfiguration {

    @Bean
    RedisConnectionFactory redisConnectionFactory() {
        // ...
    }

    @Bean
    RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {

        RedisCacheConfiguration defaults = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(5))
            .enableTimeToIdle();

        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(defaults)
            .build();
    }
}

由于 Redis 服务器没有实现正确的 TTI 概念,因此只能通过接受过期选项的 Redis 命令来实现 TTI。 在 Redis 中,“过期”在技术上是一种生存时间 (TTL) 策略。 但是,在读取键的值时可以传递 TTL 过期,从而有效地重置 TTL 过期超时,就像现在在 Spring Data Redis 的Cache.get(key)操作。spring-doc.cadn.net.cn

RedisCache.get(key)通过调用 Redis 来实现GETEX命令。spring-doc.cadn.net.cn

Redis 的GETEXcommand 仅在 Redis 版本中可用6.2.0以及后来。 因此,如果您没有使用 Redis6.2.0或更高,则无法使用 Spring Data Redis 的 TTI 过期。 如果针对不兼容的 Redis(服务器)版本启用 TTI,则会抛出命令执行异常。 没有尝试确定 Redis 服务器版本是否正确并支持GETEX命令。spring-doc.cadn.net.cn

为了在Spring Data Redis应用程序中实现真正的空闲时间(TTI)类似过期的行为,则必须在每次读取或写入作中始终以(TTL)过期的方式访问条目。 这条规则没有例外。 如果您在 Spring Data Redis 应用程序中混合和匹配不同的数据访问模式(例如:缓存,使用RedisTemplate并且可能,或者尤其是在使用 Spring Data Repository CRUD作时),那么如果设置了 TTL 过期,访问条目可能不一定会阻止该条目过期。 例如,一个条目可能会在@CacheableTTL 过期的服务方法调用(即SET <expiration options>),然后在过期超时之前使用 Spring Data Redis Repository 读取(使用GET没有过期选项)。 一个简单的GET如果不指定过期选项,则不会重置条目的 TTL 过期超时。 因此,该条目可能会在下一次数据访问作之前过期,即使它刚刚被读取。 由于无法在 Redis 服务器中强制执行此作,因此应用程序有责任在配置空闲过期时间时(在适当的情况下在缓存内外)始终如一地访问条目。spring-doc.cadn.net.cn