Redis缓存的更新策略
redis缓存是当我们有大量查询或查询较慢时,先查询缓存以减轻对数据库操作的压力。
那数据库变更后,怎么能保证缓存里的数据和数据库的数据保持一致,就需要对缓存的数据及时的更新。通常由两种方式
-
内存淘汰:redis自动进行,当redis内存达到咱们设定的max-memery的时候会自动触发淘汰机制,淘汰调一些不重要的数据。
-
超时剔除:给缓存数据添加TTL时间,到期后自动删除缓存。下次查询时更新缓存。
-
主动更新:编写业务逻辑,在修改数据库的同时,更新缓存。
如果对数据库的写操作比较频繁,那最好使用主动更新策略
但主动更新也会存在问题: 我们如果每次写操作都更新一遍缓存,但很长一段时间又没有人来查询的话,那大量的更新操作都是无效操作,所以只需要在有人查询的时候,再把数从数据库读出来存入缓存即可。
更新数据库时让缓存失效(删除缓存),查询时再更新缓存
如何保证对缓存与数据库的操作同时成功或失败?
- 单体系统,将缓存与数据库操作放在一个事务
- 分布式系统,利用TCC等分布式事务方案
那是先操作缓存还是先操作数据库呢?
其实无论是哪种方式,或多或少都会存在数据不一致问题:
- 先删缓存,再操作数据库:线程1删除了缓存还未来得及修改数据库,这中间线程2来了个查询将库中还未修改的数据写入缓存,线程1才对库进行修改。导致不一致
- 先操作数据库,再删缓存:同理会再线程1查询完数据库还未写入缓存时,线程2修改了数据库
但上述两种情况,后者的概率更小,因为写入缓存的操作要快的多,这之间很难会插入其他操作。
实例
查询过后redis中存有公司列表的缓存数据
当更新的时候,需要先更新数据库,删除缓存
@Transactional
public AjaxResult updateCompany(CompanyPo companyPo) {
if (companyPo.getId() == null) {
return AjaxResult.error("id不能为空");
}
//修改数据库
companyMapper.updateCompany(companyPo);
//删除缓存
redisTemplate.delete(Constant.REDIS_NAME + "company");
return AjaxResult.success();
}
更新后查看缓存中数据被清空