Spring缓存工作原理及@Cacheable感知数据库变更问询
Spring缓存相关问题解答
1. Spring缓存的工作机制是什么?
Spring Cache 是基于 AOP 实现的一套缓存抽象层,核心工作流程可以拆解为以下几步:
- 方法拦截:被缓存注解(如
@Cacheable)标记的方法,会被 Spring 的缓存切面拦截。 - 缓存检查:方法执行前,先根据指定的缓存名称和键,检查缓存中是否存在对应的结果:
- 如果缓存命中,直接返回缓存中的数据,跳过方法体执行;
- 如果缓存未命中,执行原始方法获取结果,再将结果存入指定缓存,供后续调用复用。
- 多缓存支持:它通过
CacheManager接口适配多种缓存实现(如 EhCache、Caffeine、Redis 等),开发者无需改动业务代码就能切换缓存提供者。 - 核心操作注解:除了
@Cacheable,还有@CacheEvict(清除缓存)、@CachePut(更新缓存)、@Caching(组合多个缓存操作)来覆盖不同的缓存场景。
2. @Cacheable注解如何感知数据库中的数据变更?
@Cacheable本身不会自动感知数据库的数据变更——它只负责读取和写入缓存,并不会主动监听数据库的变化。如果数据库数据更新后不处理缓存,就会出现缓存与数据不一致的问题。下面是几种常用的解决方案:
方案1:用@CacheEvict主动清除缓存
在修改、删除数据的业务方法上添加@CacheEvict,当这些方法执行时,自动清除对应缓存:
// 保存/更新员工时,清除整个employee缓存(因为getAllEmployees的结果是全量数据) @CacheEvict(value = "employee", allEntries = true) public Employee saveEmployee(Employee employee) { return employeeRepository.save(employee); } // 删除单个员工时,清除对应id的缓存项 @CacheEvict(value = "employee", key = "#id") public void deleteEmployee(Long id) { employeeRepository.deleteById(id); }
如果你的getAllEmployees方法是用固定键缓存的(比如key = "#root.methodName"),也可以直接指定该键进行清除,而不用清空整个缓存。
方案2:用@CachePut实时更新缓存
如果修改数据后需要直接将新结果写入缓存(而不是清除),可以用@CachePut——它会先执行方法体,再把新结果覆盖到缓存中:
@CachePut(value = "employee", key = "#employee.id") public Employee updateEmployee(Employee employee) { return employeeRepository.save(employee); }
方案3:监听数据库事件触发缓存操作
如果使用 JPA,可以监听实体的生命周期事件(如PostUpdate、PostPersist、PostRemove),在事件触发时手动操作缓存:
@Component public class EmployeeCacheListener { private final CacheManager cacheManager; public EmployeeCacheListener(CacheManager cacheManager) { this.cacheManager = cacheManager; } @EventListener public void handleEmployeeChange(AbstractEntityEvent event) { if (event.getEntity() instanceof Employee) { Cache cache = cacheManager.getCache("employee"); if (cache != null) { cache.clear(); // 或根据实体ID清除单个缓存项 } } } }
方案4:设置缓存过期时间(TTL)
如果业务允许短时间的数据不一致,可以给缓存设置过期时间。当缓存到期后自动失效,下次调用方法时会重新从数据库拉取最新数据。比如在 Redis 或 Caffeine 的配置中设置expireAfterWrite参数。
内容的提问来源于stack exchange,提问作者Geek
相关产品推荐
相关产品推荐

