Skip to content

Spring Cache

Spring Cache可以通过注解的形式实现对方法的缓存管理。
使用场景:一个方法在调用时,先从缓存获取数据,缓存有数据直接返回,缓存无数据查询数据库再返回数据,同时存储到缓存。

核心注解

  • @Cacheable:表示一个方法的返回结果会被放入缓存。在调用这个方法时,先获取缓存,如果缓存中有数据直接返回,不执行该方法;如果缓存中无数据,则执行该方法。
  • @CachePut:表示一个方法的返回结果会更新缓存。
  • @CacheEvict:表示一个方法执行后会删除缓存。
  • @Caching:组合多个缓存操作。
  • @CacheConfig:类级别共享缓存配置(如缓存名称)。@Caching允许在同一方法上使用多个嵌套的 @Cacheable@CachePut@CacheEvict注释。

POM依赖

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 使用 Redis 作为缓存实现 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

启用缓存

java
@SpringBootApplication
@EnableCaching // 开启缓存支持
public class Application { ... }

添加配置

yml
server:  
	port: 8084  
  
spring:  
	application:  
		name: springboot-cache  
	datasource:  
		url: jdbc:mysql://localhost:3306/user_db_test  
		username: root  
		password: admin123  
		type: com.zaxxer.hikari.HikariDataSource  
		driver-class-name: com.mysql.cj.jdbc.Driver  
	redis:  
		# Redis服务器地址  
		host: localhost  
		# Redis服务器连接端口  
		port: 6379  
		# Redis服务器连接密码(默认为空)  
		password: 123456
		# Redis数据库索引(默认为0)  
		database: 0  
		# 连接超时时间(毫秒)  
		timeout : 300  
		client-type: lettuce #切换jedis客户端,改成jedis  
		lettuce: #切换jedis客户端,改成jedis  
			pool:  
				# 连接池最大连接数(使用负值表示没有限制)  
				max-active: 8  
				# 连接池最大阻塞等待时间(使用负值表示没有限制)  
				max-wait: -1  
				# 连接池中的最大空闲连接  
				max-idle: 8  
				# 连接池中的最小空闲连接  
				min-idle: 0  
		cache:  
			# spring cache使用redis缓存
			# redis     # 分布式场景(推荐)
			# caffeine # 本地高性能缓存(单机)
			# ehcache  # 本地复杂缓存
			# simple   # 基于 ConcurrentHashMap 的默认实现(测试用)
			type: redis  
			redis:  
				# 是否缓存空值,防止缓存穿透  
				cache-null-values: true  
				# 缓存过期时间(单位为毫秒)  
				time-to-live: 100000  
				# 缓存前缀,用于区分其他缓存,不指定前缀,默认使用缓存的名字作为前缀  
				# key-prefix: CACHE_  
				# 是否使用缓存前缀,false不使用任何缓存前缀  
				# use-key-prefix: false

使用

java
// 查询时缓存结果(key = "product::" + 参数id)
@Cacheable(value = "product", key = "#id")
public Product getProductById(Long id) {
    return productRepository.findById(id).orElse(null);
}


// 更新数据时清除旧缓存
@CacheEvict(value = "product", key = "#product.id")
public void updateProduct(Product product) {
    productRepository.save(product);
}


// 组合操作:更新数据 + 清理列表缓存
@Caching(
    put = @CachePut(value = "product", key = "#product.id"),
    evict = @CacheEvict(value = "productList", allEntries = true)
)
public Product saveProduct(Product product) {
    return productRepository.save(product);
}

// 缓存用户推荐结果(Key: rec::用户ID::版本)
@Cacheable(value = "userRecs", key = "#userId + '::' + #version")
public List<Recommendation> getRecommendations(Long userId, String version) {
    return recommendationEngine.calculate(userId); // 复杂计算
}

自定义key

java
@Cacheable(value="users", key="#user.id") // 使用参数对象的属性
@Cacheable(value="items", key="T(String).format('ITEM:%s', #id)") // 格式化Key

条件缓存

java
// 仅当 id > 10 时缓存
@Cacheable(value="product", key="#id", condition="#id > 10")

// 结果不为 null 时缓存
@Cacheable(value="product", unless="#result == null")