@Cacheable 对数据库变更的响应机制

在Redis缓存应用,我们会出现当数据库中的数据发送变化,这会导致数据库与Redis之间数据不一致,那如何处理类似的这种问题?

@Cacheable ​不会自动监听数据库变化,它是一个被动的缓存机制,只在方法被调用时检查缓存是否存在。当数据库有新增或修改记录时,你需要主动管理缓存更新

@Cacheable ​检查的是缓存中是否存在与当前方法调用匹配的键值对,而不是简单地检查缓存是否存在。具体来说:

  • 检查缓存键(Key)是否存在
    每次调用被 @Cacheable 注解的方法时,Spring 会根据以下两个要素生成一个唯一的缓存键:

    • value/cacheNames:缓存名称(如 "users"
    • key:键表达式(如 #id,SpEL 表达式生成的键值)

    如果该键在缓存中存在,则直接返回对应的值,不执行方法体;如果不存在,才会执行方法体,并将结果存入缓存。

  • 与“缓存存在”的区别
    “缓存存在”指的是 Redis 中是否有对应的数据库或存储空间,而 @Cacheable 检查的是缓存中是否存在特定键值对。例如:

被动触发机制
@Cacheable 不会主动轮询或监听数据库变化,只有通过方法调用才会触发缓存检查。这意味着:

  • 如果数据库数据变化但未调用相关方法,缓存不会更新。
  • 即使数据库变化后调用了其他方法(如新增数据的方法),只要不触发带有 @Cacheable 的方法,缓存依然不会更新。

如何保持缓存与数据一致

1.手动清除缓存(推荐)

在修改数据的方法上添加 @CacheEvict,强制清除旧缓存:

@CacheEvict(value = "users", key = "#id")
public void updateUser(Long id, User user) {
    userRepository.save(user);
}

在方法没有参数的情况下,如果要清除固定键 userList::cacheRedis 的缓存,可以通过以下方式实现:

直接在 @CacheEvict 注解中 ​显式指定固定键值,配合 value 指定缓存名称:

@CacheEvict(value = "userList", key = "'cacheRedis'")
public void updateUser() {
    // 数据库更新操作
    // userRepository.save(...);
}

 

场景 实现方式
固定键缓存 @Cacheable(value = "userList", key = "'cacheRedis'")
无参数方法清除缓存 @CacheEvict(value = "userList", key = "'cacheRedis'")
清除整个缓存区域 @CacheEvict(value = "userList", allEntries = true)

通过显式指定固定键值,即使方法没有参数,也能精准清除目标缓存条目。

 

2.设置缓存过期时间(TTL)

通过 Redis 配置,让缓存自动过期并重新加载:

@Configuration
@EnableCaching
public class RedisConfig {
    @Bean
    public RedisCacheManagerBuilderCustomizer ttlCustomizer() {
        return builder -> builder
            .withCacheConfiguration("users",
                RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofMinutes(30)) // 30分钟过期
            );
    }
}

 

posted @ 2025-05-13 10:33  子墨老师  阅读(58)  评论(0)    收藏  举报