实战篇 12. 附近商铺 - 导入店铺数据到 GEO (缓存预热)

0 阅读3分钟

太棒了!掌握了 GEO 的基础命令后,我们现在要真刀真枪地把 MySQL 里的商铺数据“搬”到 Redis 里了。

这部分不仅仅是一段简单的数据同步代码,其中隐藏的**“大 Key 拆分”“批量操作”**思想,绝对是你在接下来的实习面试和秋招中,面对面试官拷问项目细节时非常棒的亮眼谈资。


📚 实战篇 12. 附近商铺 - 导入店铺数据到 GEO (缓存预热)

一、 核心架构思考:如何设计 Redis Key?

在把商铺的经纬度存入 Redis 之前,我们面临着一个极其重要的架构抉择:所有的商铺存入同一个 Key,还是分开存?

❌ 错误方案:全部存入一个 Key (shop:geo:all)

如果你的项目扩展到全国,有几百万家商铺,把它们全部塞进一个 ZSet(GEO 的底层)中,会导致这个 Key 的体积极其巨大。这就是 Redis 中极其致命的**“大 Key (Big Key) 问题”**。大 Key 在进行扩容、迁移或删除时,会引发极其严重的单线程阻塞,导致整个 Redis 瞬间瘫痪。

✅ 正确方案:按商铺类型 (Type) 分组拆分

在黑马点评的实际业务中,用户搜索附近商铺时,通常是分类搜索的(比如“附近的烤肉”、“附近的 KTV”)。因此,我们完美的解决方案是:按照商铺的 type_id 进行分组存储。

  • Key 的设计: shop:geo:{typeId} (例如 shop:geo:1 代表美食,shop:geo:2 代表 KTV)。
  • 优势: 既贴合了业务查询场景,又完美规避了 Redis 的大 Key 问题。

二、 核心代码落地 (Spring Boot 单元测试)

由于“导入商铺数据”属于项目的**缓存预热(Cache Warm-up)**工作,通常只需要在系统上线前或后台管理系统中执行一次即可。因此,我们通常把它写在一个 @Test 测试方法中。

这里结合了 Java 8 的 Stream 流操作和 Spring Data Redis 的高阶用法:


三、 面试高频考点深度剖析 (简历防身必看)

这段代码虽然不长,但如果面试官深挖,这里有一个极其经典的网络性能考点。

💥 夺命连环问:为什么不在 3.5 步的 for 循环里,直接调用 stringRedisTemplate.opsForGeo().add(key, point, member) 一条条往 Redis 里塞?而是要搞个 locations 集合最后在 3.6 步统一提交?

你的标准满分回答:

“因为如果放在 for 循环里逐条写入,假设该分类下有 1000 家商铺,就会产生 1000 次网络 I/O 开销。在微服务架构中,频繁的网络请求(即使在内网)耗时是非常巨大的(每次都要建立连接、发送命令、等待响应)。

而使用 locations 集合统一收集后调用批处理 API(底层实际上会向 Redis 发送一条包含多个参数的 GEOADD key lon1 lat1 mem1 lon2 lat2 mem2 ... 命令),将 1000 次网络请求压缩成了 1 次。这极大地减少了网络往返时间(RTT),是提高 Redis 写入吞吐量的标准做法。”


学习总结

通过这一步的缓存预热,你不仅将关系型数据库中的沉重数据巧妙地转化为了 Redis 内存中的空间索引,还利用了**数据拆分(规避大 Key)批处理(降低网络 I/O)**两大企业级优化思想。

把这段逻辑吃透,它完全可以作为你简历中“黑马点评项目”的一个性能优化小亮点,展示你扎实的代码内功!