一、@Cacheable:数据查询的 “性能加速器”

在高频查询场景中,反复访问数据库会导致系统响应迟缓,@Cacheable就像一个智能数据仓库,能将首次查询的结果缓存起来,后续相同请求直接从缓存获取,瞬间提升接口响应速度。它通过注解配置即可生效,无需手动编写复杂的缓存逻辑,是 Spring Boot 性能优化的常用利器。

要使用@Cacheable,首先需要在启动类上添加@EnableCaching注解开启缓存功能:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCaching // 开启缓存支持
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class, args);
    }
}

二、基础用法:简单配置实现缓存

@Cacheable的核心是指定缓存名称,通过value或cacheNames属性定义,Spring Boot 默认使用 ConcurrentHashMap 作为缓存容器(生产环境可替换为 Redis 等分布式缓存)。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // 将查询结果缓存到名为"userCache"的缓存中
    @Cacheable(value = "userCache", key = "#id")
    public User getUserById(Long id) {
        // 模拟数据库查询(实际开发中此处是JDBC或ORM操作)
        System.out.println("从数据库查询用户,ID:" + id);
        User user = new User();
        user.setId(id);
        user.setName("用户" + id);
        user.setAge(20 + (int)(id % 10));
        return user;
    }
}

// 实体类定义
import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
}

当首次调用getUserById(1L)时,控制台会输出 “从数据库查询用户,ID:1”,并将结果存入userCache;再次调用该方法时,直接从缓存获取数据,不会执行方法体内的数据库查询逻辑。

三、高级配置:精准控制缓存行为

1. 条件缓存:按需决定是否缓存

通过condition属性设置条件,只有满足条件的请求才会被缓存;unless属性则相反,满足条件时不缓存。

@Service
public class ProductService {

    // 只缓存价格大于100的商品(condition表达式基于方法参数)
    @Cacheable(value = "productCache", key = "#id", condition = "#price > 100")
    public Product getProductById(Long id, BigDecimal price) {
        System.out.println("从数据库查询商品,ID:" + id);
        Product product = new Product();
        product.setId(id);
        product.setName("商品" + id);
        product.setPrice(price);
        return product;
    }

    // 不缓存库存为0的商品(unless表达式基于返回结果)
    @Cacheable(value = "productCache", key = "#id", unless = "#result.stock == 0")
    public Product getProductWithStock(Long id) {
        System.out.println("从数据库查询带库存商品,ID:" + id);
        Product product = new Product();
        product.setId(id);
        product.setName("库存商品" + id);
        product.setStock((int)(id % 5)); // 模拟库存
        return product;
    }
}

2. 自定义缓存 key 生成策略

除了用key属性手动指定,还能通过实现KeyGenerator接口自定义全局 key 生成规则,或使用 SpEL 表达式灵活构建 key。

// 复杂参数场景的key构建
@Cacheable(value = "orderCache", key = "#orderNo + '-' + #userId")
public Order getOrderByNoAndUserId(String orderNo, Long userId) {
    System.out.println("从数据库查询订单,订单号:" + orderNo + ",用户ID:" + userId);
    // 模拟数据库查询逻辑
    Order order = new Order();
    order.setOrderNo(orderNo);
    order.setUserId(userId);
    order.setAmount(new BigDecimal("200.00"));
    return order;
}

四、缓存联动:与其他缓存注解配合使用

@Cacheable常与@CacheEvict(清除缓存)、@CachePut(更新缓存)配合,确保缓存数据与数据库数据一致性。

@Service
public class UserService {

    // 新增缓存
    @Cacheable(value = "userCache", key = "#id")
    public User getUserById(Long id) {
        // 数据库查询逻辑...
    }

    // 更新用户信息后清除对应缓存
    @CacheEvict(value = "userCache", key = "#user.id")
    public void updateUser(User user) {
        System.out.println("更新数据库用户信息,ID:" + user.getId());
        // 数据库更新逻辑...
    }

    // 删除用户后清除对应缓存
    @CacheEvict(value = "userCache", key = "#id")
    public void deleteUser(Long id) {
        System.out.println("从数据库删除用户,ID:" + id);
        // 数据库删除逻辑...
    }

    // 新增用户并缓存(CachePut会执行方法并更新缓存)
    @CachePut(value = "userCache", key = "#result.id")
    public User addUser(User user) {
        System.out.println("向数据库新增用户");
        // 数据库插入逻辑(假设插入后生成ID)
        user.setId(System.currentTimeMillis());
        return user;
    }
}

五、分布式缓存适配:对接 Redis

生产环境中,单机缓存无法满足集群部署需求,可通过整合 Redis 实现分布式缓存。只需添加 Redis 依赖并配置连接信息,@Cacheable无需修改代码即可无缝切换。

1. 添加依赖(Maven)

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

2. 配置 Redis 连接

spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0

此时,@Cacheable的缓存数据会存储在 Redis 中,不同服务实例可共享缓存,避免集群环境下的缓存不一致问题。

@Cacheable以极简的配置实现了高效的缓存功能,无论是单机还是分布式系统,都能显著降低数据库压力、提升系统吞吐量。合理运用其条件缓存、key 定制等高级特性,能让缓存策略更贴合业务需求,成为 Spring Boot 性能优化的得力助手。