苍穹外卖-缓存套餐 Spring Cache day07
Spring Cache 是 Spring 框架提供的一个缓存抽象层,它通过注解的方式简化了缓存的使用,支持多种缓存实现(如 Caffeine、Redis、EhCache 等),并统一了缓存访问的 API。以下是关于 Spring Cache 的详细介绍:
核心注解
@EnableCaching:用于开启 Spring Cache 功能,通常放在配置类上。
@Cacheable:标记方法具有缓存功能,方法的返回值会被缓存。若缓存中有数据则直接返回,否则执行方法并将结果缓存。
@CachePut:每次执行都会将方法的返回值放入缓存,无论缓存中是否已存在数据,常用于更新操作。
@CacheEvict:用于清除指定缓存,常用于删除操作。
@Caching:组合注解,可同时指定多个缓存规则,如同时使用 @Cacheable、@CachePut 和 @CacheEvict。
@CacheConfig:类级别注解,用于简化缓存配置,可在类级别定义公共的缓存配置属性。
基本使用步骤
添加依赖:如果是 Spring Boot 项目,可使用
spring-boot-starter-cache
Starter。启用缓存:在配置类上添加
@EnableCaching
注解。配置 CacheManager:需注册一个
CacheManager
,如ConcurrentMapCacheManager
。使用注解:在方法上使用上述注解来声明缓存规则
缓存穿透
定义:查询的Key在缓存和数据库中都不存在,导致每次请求都直接访问数据库,若大量此类请求到来,会使数据库压力骤增。
成因:
业务误操作,导致缓存和数据库中的数据都被误删除。
黑客恶意攻击,故意大量访问不存在的数据。
解决方案:
缓存空对象:当查询不到数据时,将空对象或标识存储到缓存中,但需注意设置较短的过期时间,避免过多无用数据占用缓存空间。
布隆过滤器:预先将所有可能存在的数据通过哈希函数映射到一个足够大的Bitmap中,查询时先通过布隆过滤器判断数据是否存在,若布隆过滤器返回不存在,则直接返回,避免查询数据库。
参数校验:在接口层增加严格的参数校验,如用户鉴权校验,拦截非法请求。
限流和熔断:对访问频率进行限制,当请求量超过阈值时,直接拒绝请求或返回默认值,防止数据库被过多请求冲击。
缓存击穿
定义:缓存中的某个热点数据失效,大量请求同时访问该数据,导致请求直接穿透到数据库,给数据库带来巨大压力。
成因:
缓存中没有热点数据的缓存,或缓存穿透导致热点数据未被缓存。
解决方案:
热点数据永不过期:对热点数据设置永不过期,避免其在缓存中失效,但需定期更新数据,以确保缓存数据的时效性。
互斥锁机制:在缓存失效时,使用互斥锁或分布式锁,确保只有一个请求去查询数据库并更新缓存,其他请求等待锁释放后再从缓存中读取数据。
缓存雪崩
定义:大量缓存数据在同一时间过期,导致大量请求同时到达数据库,给数据库带来巨大压力,甚至可能导致数据库崩溃。
成因:
缓存过期策略不当,导致大量缓存同时过期。
缓存服务器宕机。
解决方案:
设置不同的过期时间:为不同缓存设置不同的过期时间,避免大量缓存同时失效。
过期时间加随机数:在设置的过期时间基础上,再加一个随机数,使缓存的过期时间分散。
缓存预热:在系统启动时,预先将热点数据加载到缓存中。
限流和熔断:对访问频率进行限制,当请求量超过阈值时,直接拒绝请求或返回默认值,防止数据库被过多请求冲击。
本地缓存:在分布式缓存的基础上,增加本地缓存,提高缓存的可用性。
双缓存:使用两层缓存,第一层缓存使用本地缓存,第二层缓存使用分布式缓存,当第一层缓存失效时,可以由第二层缓存提供数据。
利用Redis集群:提高缓存服务的可用性,即使部分节点失效,也不会影响整个缓存系统的可用性
入门案例:
package com.itheima.controller;import com.itheima.entity.User;
import com.itheima.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {@Autowiredprivate UserMapper userMapper;@PostMapping
// @CachePut(cacheNames = "userCache",key = "#a0.id")//spring cache缓存
// @CachePut(cacheNames = "userCache",key = "#p0.id")//spring cache缓存
// @CachePut(cacheNames = "userCache",key = "#result.id")//spring cache缓存@CachePut(cacheNames = "userCache",key = "#user.id")//spring cache缓存public User save(@RequestBody User user){userMapper.insert(user);return user;}@DeleteMapping@CacheEvict(cacheNames = "userCache",key = "#id")public void deleteById(Long id){userMapper.deleteById(id);}@DeleteMapping("/delAll")@CacheEvict(cacheNames = "userCache",allEntries = true)public void deleteAll(){userMapper.deleteAll();}@GetMapping@Cacheable(cacheNames = "userCache",key = "#id")public User getById(Long id){User user = userMapper.getById(id);return user;}}