一、@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 性能优化的得力助手。
















