缓存

缓存抽象与依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Spring 缓存抽象把「缓存管理」与具体存储解耦。不额外配置时,Boot 默认使用基于 ConcurrentHashMap 的进程内缓存(重启即失);要存进 Redis,只需让 spring-boot-starter-data-redis 也在类路径,并设置 spring.cache.type=redis。加一个配置类开启缓存:

@Configuration
@EnableCaching
public class CacheConfig {
}

三个核心注解

注解行为
@Cacheable先查缓存,命中直接返回;未命中执行方法并把结果写入缓存
@CachePut总是执行方法,并用返回值更新缓存(写操作后刷新缓存)
@CacheEvict执行方法并删除缓存(配合删除操作)

常用参数:cacheNames(缓存分区名)、key(SpEL 表达式,如 #id)、condition(执行前判断是否走缓存)、unless(返回后判断是否不写缓存,如 unless = "#result == null")。多个注解组合用 @Caching

完整示例

@Service
public class UserService {

    @Cacheable(cacheNames = "user", key = "#id")
    public User findById(Long id) {
        return userDao.findById(id);   // 首次查库,之后同 key 命中缓存
    }

    @CacheEvict(cacheNames = "user", key = "#id")
    public void deleteById(Long id) {
        userDao.deleteById(id);        // 删除数据同时清掉缓存
    }

    @CachePut(cacheNames = "user", key = "#user.id")
    public User save(User user) {
        return userDao.save(user);     // 更新数据并刷新缓存
    }
}

调用链效果:findById(1) 第一次执行方法并缓存;第二次同参数直接返回缓存值;save/delete 后缓存与数据库保持一致。

配置示例

spring.cache.type=redis            # 缓存到 Redis
spring.cache.cache-names=user,role # 预声明缓存分区

Redis 模式下缓存对象的序列化方式、TTL、前缀等配置(如 spring.cache.redis.*)以官方文档为准。

失效场景与注意

  • 自调用不走代理:同类内部直接调 findById 不经缓存代理,注解不生效(与 17 章事务同理);
  • key 不写时默认用方法参数生成 SimpleKey,多参数方法建议显式写 key;
  • 对象缓存到 Redis 时默认 JDK 序列化,跨语言/排查不便,生产建议配置 JSON 序列化;
  • 缓存与数据库的强一致需要结合 @CacheEvict/@CachePut 的失效策略与业务容忍度权衡;
  • 多实例部署时进程内缓存各实例独立,建议直接使用 Redis 缓存。

小结

缓存抽象四步:加 starter、开 @EnableCaching、注解声明、选缓存后端。读多写少的查询用 @Cacheable,写操作配合 @CachePut/@CacheEvict 维护一致性,就能以很小成本拿到可观收益。

笔记加载中…