本章节使用了 Spring Boot、MyBatis-Plus、Redis 和 MySQL,实现了商品的查询缓存与更新。
Cache Aside 模式
Cache Aside 模式就是“旁路缓存”模式:
- 根据商品 ID 在 Redis 中查询商品详情信息。
- Redis 命中时,直接返回商品信息。
- Redis 未命中时,查询 MySQL。
- MySQL 查询到商品后,将商品信息写入 Redis 并设置 TTL,以便下次查询。
- MySQL 未查询到商品时,将空值写入 Redis,并设置较短的 TTL,避免相同请求反复查询数据库。
- 返回查询结果。
查询流程
Redis → 未命中 → MySQL → 回填 Redis
更新流程
更新 MySQL → 删除 Redis 缓存 → 下次查询时回填 Redis
商品信息在 Redis 的存储
当前使用
StringRedisTemplate 将商品序列化成 JSON 字符串后存入 Redis,读取时再反序列化。也可以使用 Redis Hash 存储商品信息。
两者的区别:
- JSON 比较适合整体读取和整体更新,使用简单。
- Hash 适合单独读取或更新某一个字段。
本文主要用于学习和体会缓存流程,当前没有高频读取或单独修改某个字段的需求,因此使用 JSON 字符串存储。
TTL
TTL 是 Redis 中的过期时间。在本次学习中,写入缓存时需要设置过期时间,避免缓存永久留存。实际项目中可以根据数据的变化频率设置 TTL;商品信息变化不频繁时,可以适当延长过期时间。
缓存穿透
缓存穿透是指查询不存在的数据:
Redis 中不存在 → MySQL 中也不存在 → 每次请求都访问 MySQL
如果不进行处理,每次请求都会查询 MySQL,持续增加数据库压力。
本次采用缓存空值的方式处理:
- Redis 返回
null:表示没有缓存,需要查询 MySQL。
- Redis 返回空字符串:表示该商品不存在,直接返回。
- Redis 返回 JSON 字符串:反序列化后返回。
不存在的商品在缓存时应选择较短的 TTL,避免商品信息更新不及时,商品创建后仍长时间查询不到。
空值缓存只能防止同一个无效 ID 被反复查询。面对大量随机 ID 时,可以使用布隆过滤器。
缓存一致性
更新商品时不能只更新 MySQL,否则可能返回旧数据。
本次采用:
更新 MySQL → 更新成功 → 删除 Redis 缓存
没有选择同时更新 MySQL 和 Redis,是因为两个系统无法通过普通数据库事务保证同时成功。因此采用删除缓存的方式,在下次查询时自动重建缓存。
@Transactional 主要管理 MySQL 事务,不能让 Redis 操作一起回滚。后续优化方向
- 给 TTL 增加随机值,避免同一时间大量缓存到期而造成缓存雪崩。
- 使用布隆过滤器拦截大量无效 ID。
- 对缓存删除失败增加重试机制或引入消息队列。
- 数据适合按字段操作时,将存储方式调整为 Redis Hash。
总结
读数据:先查 Redis,未命中再查 MySQL并回填缓存。
写数据:先更新 MySQL,更新成功后删除 Redis 缓存。
- Author:程知非
- URL:http://preview.tangly1024.com/article/3b1387f8-af4f-800c-9303-cf9cd765d898
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!


