RSS
菜单
全部文章快讯开发科技深度热点

第 33 章 京东系MySQL真题精讲

内容摘要

京东系(自营电商/物流/大促)面试的 MySQL 题聚焦"电商交易链路与大促"——库存扣减、订单快照、SKU/SPU、购物车、支付回调、履约、热点商品、双写迁移。本篇精选 20 道公开高频题型,覆盖大促库存预占、超时关单、商品数据模型、跨分片商家查询、ES 同步、热点行优化。题目均为公开面经常见类型,解析讲通用原理,不涉及任何公司未公开信息。前置知识:第 3、5、17、18、23 章;本系列示例基于 MySQL 8.0。

📖 本篇简介:京东系(自营电商/物流/大促)面试的 MySQL 题聚焦"电商交易链路与大促"——库存扣减、订单快照、SKU/SPU、购物车、支付回调、履约、热点商品、双写迁移。本篇精选 20 道公开高频题型,覆盖大促库存预占、超时关单、商品数据模型、跨分片商家查询、ES 同步、热点行优化。题目均为公开面经常见类型,解析讲通用原理,不涉及任何公司未公开信息。前置知识:第 3、5、17、18、23 章;本系列示例基于 MySQL 8.0。

目录

  • 1 本篇考情与知识地图
  • 题目 1:大促库存扣减方案怎么设计
  • 题目 2:订单超时关单怎么实现
  • 题目 3:购物车表怎么设计
  • 题目 4:商品SPU和SKU数据模型
  • 题目 5:分库分表后商家维度查询怎么办
  • 题目 6:价格变动为什么要订单快照
  • 题目 7:支付回调如何幂等
  • 题目 8:大促前数据库要做哪些准备
  • 题目 9:库存预占与回滚怎么设计
  • 题目 10:海量评论晒单数据怎么存
  • 题目 11:商品搜索和商品库怎么同步
  • 题目 12:订单履约状态机怎么流转
  • 题目 13:秒杀系统DB层怎么扛
  • 题目 14:分库分表扩容双写怎么做
  • 题目 15:热点商品行锁竞争怎么优化
  • 题目 16:业务库和数仓怎么分工
  • 题目 17:大促期间DB层限流降级
  • 题目 18:订单多条件查询索引设计
  • 题目 19:MySQL同步ES如何保证一致
  • 题目 20:电商MySQL架构怎么演进
  • 速查速记
  • 常见坑与注意事项
  • 复习清单
  • 练习题

1 本篇考情与知识地图

京东系面试围绕"一笔自营订单从加购、下单、支付、发货到签收",核心是库存准、价格快照、大促扛得住。先建地图:

| 链路环节 | 数据问题 | 手段 |

|---|---|---|

| 加购 | 购物车 | 轻量表+缓存 |

| 下单 | 库存预占 | 原子扣减 |

| 支付 | 回调幂等 | 状态机 |

| 履约 | 状态流转 | 事件驱动 |

| 搜索 | 多条件 | ES 同步 |

主线:库存和价格这两样不能错,大促要提前把洪峰挡在数据库之外。

题目 1:大促库存扣减方案怎么设计

考点

  • 预占;原子;Redis 前置。

参考答案

1. 下单预占:下单即冻结库存,WHERE stock>0 原子扣;

2. 支付确认:预转给实扣;未支付超时释放;

3. 大促前置 Redis:热点商品库存放 Redis,Lua 原子扣,异步落 DB;

4. 限流排队:网关限流,DB 按可承受速率消费;

5. 对账:Redis 与 DB 库存定时核对。

-- 预占库存:冻结而非实扣,本示例基于 MySQL 8.0
UPDATE t_sku_stock
SET locked = locked + 1, update_time = NOW()
WHERE sku_id = 66 AND stock - locked >= 1;  -- 可用库存=stock-locked

追问

  • 问:可用库存怎么算?答:可用 = 总库存 - 已锁定,扣减条件用可用判断。
  • 问:超卖了?答:条件原子判断 + 对账兜底纠正。

题目 2:订单超时关单怎么实现

考点

  • 延迟任务;释放库存。

参考答案

1. 延迟队列:下单发延迟消息,到点检查是否支付;

2. 定时扫单兜底:扫超时未支付单;

3. 条件关单:WHERE status=待支付,已支付不动;

4. 释放预占库存:关单同时回补;

5. 幂等:重复关单影响 0 行。

追问

  • 问:延迟队列丢了?答:定时扫单兜底。
  • 问:关单瞬间用户付款?答:以支付为准,关单条件判断+支付回调抢先,靠状态机收敛。

题目 3:购物车表怎么设计

考点

  • 轻量;合并。

参考答案

1. 一行一个购物项:(user_id, sku_id, quantity, selected);

2. 按 user_id 查询:进购物车一次拉出;

3. 登录/未登录合并:未登录存 Redis,登录后合并;

4. 价格实时算:购物车不存价格,展示时实时查商品;

5. 量大:购物车数据放 Redis,DB 持久化登录态。

追问

  • 问:购物车要存商品快照吗?答:不存,下单那一刻才生成订单快照。
  • 问:购物车太多商品?答:分页/折叠,Redis 扛。

题目 4:商品SPU和SKU数据模型

考点

  • 商品建模;主从。

参考答案

1. SPU:标准产品单元,描述一款商品(如"某手机"),存公共属性;

2. SKU:最小存货单位,具体规格(颜色/内存),存价格、库存、图片;

3. 一对多:一个 SPU 多个 SKU;

4. 属性表:SPU 扩展属性用键值表或 JSON;

5. 索引:SKU 按 spu_id 查,商品搜索靠 ES。

-- SPU 与 SKU,本示例基于 MySQL 8.0
CREATE TABLE t_spu (spu_id BIGINT PRIMARY KEY, title VARCHAR(200), brand_id BIGINT);
CREATE TABLE t_sku (
  sku_id BIGINT PRIMARY KEY, spu_id BIGINT, price DECIMAL(10,2),
  stock INT, spec VARCHAR(100), KEY idx_spu(spu_id)
);

追问

  • 问:规格属性怎么存?答:固定高频列建字段,长尾属性存 JSON。
  • 问:商品详情怎么查?答:SPU + 多个 SKU 一次聚合,挡缓存。

题目 5:分库分表后商家维度查询怎么办

考点

  • 路由表;ES。

参考答案

1. 订单按 user_id 分片(C 端量大);

2. 商家查订单:建 merchant_id → order_id 路由索引表,或同步 ES;

3. 商家后台多条件:全走 ES;

4. 避免跨分片大聚合:商家报表走数仓;

5. 冗余:订单表冗余 merchant_id 便于过滤。

追问

  • 问:商家要实时看今天单量?答:Redis 计数 + ES,别跨分片 count。
  • 问:路由索引表膨胀?答:按 merchant_id 分片或只留近期。

题目 6:价格变动为什么要订单快照

考点

  • 快照设计;历史价。

参考答案

1. 商品价格会变:下单时必须把价格、名称、规格快照进订单;

2. 快照存订单明细行:订单明细表冗余商品当时信息;

3. 不联商品表:后续改价/下架不影响历史订单;

4. 退款按快照价算;

5. 商品主表仍存现价,订单存历史价。

追问

  • 问:快照冗余不会不一致?答:下单那一刻固化,之后不改,天然一致。
  • 问:快照字段太多?答:只冗余展示/结算必需字段。

题目 7:支付回调如何幂等

考点

  • 回调重试;状态机。

参考答案

1. 支付单号唯一:一笔订单一个支付单号;

2. 条件更新:UPDATE order SET status=已支付 WHERE id=? AND status=待支付;

3. 回调重复:已支付后再回调影响 0 行,不重复入账;

4. 回调验签:校验支付平台签名,防伪造;

5. 对账兜底:与支付平台对账。

追问

  • 问:回调乱序(成功通知比失败晚到)?答:状态机只允许前进,已支付不再回退。
  • 问:本地还没收到回调用户已付款?答:主动查单补偿。

题目 8:大促前数据库要做哪些准备

考点

  • 容量;预热;预案。

参考答案

1. 压测:按预估峰值压测,找出瓶颈;

2. 容量冗余:CPU 水位留缓冲,加只读副本;

3. 缓存预热:热点商品/库存进 Redis;

4. 索引审查:慢 SQL 提前优化;

5. 预案演练:限流、降级、切换、扩容演练;

6. 值守:大盘监控 + 值班 + 应急预案。

追问

  • 问:临时加机器来得及吗?答:只读副本加了就能分担读,写扩容要提前。
  • 问:大促中发现慢 SQL?答:先 kill 止血,再灰度优化。

题目 9:库存预占与回滚怎么设计

考点

  • 预占流水;释放。

参考答案

1. 预占记录:下单写一条库存冻结记录;

2. 支付成功:冻结转实扣;

3. 超时/取消:冻结释放回可用;

4. 原子操作:冻结/释放都用条件更新防超卖;

5. 对账:冻结量与在途订单对账。

追问

  • 问:预占和实扣两次更新?答:是的,预占防超卖,实扣是最终态。
  • 问:并发释放?答:条件更新,避免重复释放多补库存。

题目 10:海量评论晒单数据怎么存

考点

  • 评论量大;归档。

参考答案

1. 按 spu_id 分片:某商品评论落固定分片;

2. 分页游标:按评论 ID/时间游标翻页;

3. 热度评论缓存:热门评价挡 Redis;

4. 归档:老商品评论归档;

5. 晒图存 OSS:图片存 OSS,DB 存 URL。

追问

  • 问:评论数怎么统计?答:Redis 计数 + 商品表冗余 comment_count。
  • 问:差评过滤?答:在 DB/ES 按评分过滤,别全拉回内存筛。

题目 11:商品搜索和商品库怎么同步

考点

  • binlog 同步;ES。

参考答案

1. 商品库是权威源:ES 是派生索引;

2. binlog 订阅:Canal 监听商品 binlog 异步更新 ES;

3. 全量 + 增量:定期全量校准,实时增量更新;

4. 一致性容忍:ES 短时间延迟可接受;

5. 对账:ES 文档数与商品数定期核对。

追问

  • 问:ES 挂了搜索?答:降级到 DB 简单筛选,不可用则搜索暂不可用。
  • 问:商品改了 ES 没更新?答:binlog 延迟,定期全量校准。

题目 12:订单履约状态机怎么流转

考点

  • 履约节点;事件驱动。

参考答案

1. 节点:已付款 → 拣货 → 出库 → 配送 → 签收;

2. 事件驱动:物流事件驱动订单状态流转;

3. 条件更新:每个流转带旧状态条件;

4. 状态流水:每节点记一条,便于追踪;

5. 幂等:重复事件不重复推进。

追问

  • 问:物流系统和订单系统不一致?答:以物流事件为准驱动,定期对账。
  • 问:拒收退货?答:进入逆向退款分支状态机。

题目 13:秒杀系统DB层怎么扛

考点

  • 分层拦截;DB 减压。

参考答案

1. 前端限流:按钮置灰、答题/验证码挡机器人;

2. Redis 预扣库存:DB 不直接扛洪峰;

3. MQ 排队下单:异步落库,DB 匀速消费;

4. DB 原子扣:最终在 DB 核对防超卖;

5. 降级:Redis/MQ 出问题直接限流停秒。

追问

  • 问:DB 层做了什么?答:只在异步队列里做最终扣减,不被瞬时流量打穿。
  • 问:超卖兜底?答:DB WHERE stock>0 条件 + 对账。

题目 14:分库分表扩容双写怎么做

考点

  • 不停机扩容;校验切流。

参考答案

1. 新分片就绪;

2. 双写:新写同时写新旧;

3. 存量迁移 + binlog 追平;

4. 校验:count/checksum 一致;

5. 灰度切读切写:观察无误后全切,老库只读下线。

追问

  • 问:双写两边都写成功?答:以一边为准,另一边补偿;不能让两分支不一致。
  • 问:怎么切最稳?答:先切读流量灰度,再切写。

题目 15:热点商品行锁竞争怎么优化

考点

  • 单行锁;分桶。

参考答案

1. 库存分桶:一个商品库存拆多行,请求随机路由,打散行锁;

2. 库存前置 Redis:热点直接在 Redis 扣;

3. 缩短事务:扣减不夹带其他操作;

4. 批量异步:计数类合并刷回;

5. 大促前隔离:热点商品单独资源池。

追问

  • 问:分桶后怎么看总库存?答:SUM 或 Redis 维护总数。
  • 问:还不够?答:热点库存全放 Redis,DB 只做对账快照。

题目 16:业务库和数仓怎么分工

考点

  • OLTP vs OLAP。

参考答案

1. 业务库 MySQL:事务、点查、低延迟;

2. 数仓:报表、聚合、离线分析;

3. 数据同步:业务库 binlog → 数仓;

4. 别在业务库跑大报表:拖垮在线;

5. 宽表:分析用宽表在数仓建好。

追问

  • 问:运营要实时报表?答:实时数仓(ClickHouse),别查 MySQL。
  • 问:为什么不在 MySQL 做分析?答:行存 + 事务,聚合扫描慢。

题目 17:大促期间DB层限流降级

考点

  • 自我保护。

参考答案

1. 限流:DB QPS/连接到阈值,网关/应用层限流;

2. 降级:非核心功能(推荐、评价)暂时关闭;

3. 读降级:读超时走缓存兜底值;

4. 写降级:超卖商品直接售罄,不进扣减;

5. 保核心:保下单/支付主链路。

追问

  • 问:限流在 DB 层还是上游?答:尽量上游(网关),别让请求打到 DB 才拒绝。
  • 问:降级开关?答:配置中心一键开关,提前演练。

题目 18:订单多条件查询索引设计

考点

  • 用户侧查询;联合索引。

参考答案

1. 我的订单:(user_id, status, created_at) 联合索引;

2. 按时间倒序:索引顺序匹配排序,免 filesort;

3. 运营多条件:走 ES;

4. 深分页:游标分页;

5. 覆盖:列表展示字段尽量覆盖索引。

-- 我的订单列表索引,本示例基于 MySQL 8.0
-- 查询:WHERE user_id=? AND status=? ORDER BY created_at DESC LIMIT ?,20
-- 索引:(user_id, status, created_at)

追问

  • 问:用户查全部状态订单?答:status 可选,把等值 user_id 放最前,created_at 排序。
  • 问:按订单号查?答:order_no 唯一索引。

题目 19:MySQL同步ES如何保证一致

考点

  • binlog;对账;延迟。

参考答案

1. binlog 订阅增量同步:商品变更实时进 ES;

2. 全量校准:定期全量重建 ES;

3. 容忍延迟:搜索结果短时间延迟可接受;

4. 失败重试:同步失败进队列重试;

5. 对账:ES 与 DB 文档数比对。

追问

  • 问:ES 数据错了?答:全量重建对应商品。
  • 问:同步和事务一致?答:做不到强一致,靠最终一致 + 对账。

题目 20:电商MySQL架构怎么演进

考点

  • 演进路径。

参考答案

1. 初期:单库单表;

2. 增长:读写分离 + 缓存;

3. 瓶颈:垂直拆库(商品/订单/支付);

4. 再增长:订单分库分表 + ES;

5. 大促:库存前置 Redis、MQ 削峰、限流降级;

6. 原则:按需演进,别过度设计。

追问

  • 问:什么时候分库分表?答:单表千万、单库 CPU/IO 瓶颈,纵向升配不划算。
  • 问:演进中最大的坑?答:扩容迁移、跨库事务、数据一致性。

速查速记

| 环节 | 方案 | 关键点 |

|---|---|---|

| 库存 | 预占+原子扣 | 可用=总-锁 |

| 价格 | 订单快照 | 下单固化 |

| 回调 | 条件更新幂等 | 验签+对账 |

| 搜索 | binlog同步ES | 全量校准 |

| 热点 | Redis前置+分桶 | DB最终核对 |

| 大促 | 压测+预热+限流 | 保主链路 |

| 演进 | 单库→读写→拆库→分片 | 按需 |

常见坑与注意事项

  • 坑 1:购物车/订单直接用商品现价——商品改价后历史订单价错乱,必须快照;
  • 坑 2:支付回调无条件更新——重复回调重复入账,必须带状态条件;
  • 坑 3:热点商品单行扣库存——行锁串行,大促必崩,前置 Redis;
  • 坑 4:运营多条件检索压 MySQL——跨分片聚合慢,走 ES/数仓;
  • 坑 5:ES 当权威源——ES 是派生索引,商品数据以 MySQL 为准;
  • 注意:本篇均为公开题型与通用电商架构,不代表任何公司真实系统。

复习清单

| 题目 | 核心结论 | 易错点 |

|---|---|---|

| 库存 | 预占+原子 | 可用=总-锁 |

| 快照 | 下单固化价格 | 别联商品表 |

| 支付回调 | 条件更新+验签 | 别重复入账 |

| SKU/SPU | 一对多 | 属性用JSON |

| 热点 | Redis前置 | 别单行硬扣 |

| 搜索同步 | binlog+校准 | ES非权威 |

| 大促 | 压测预热限流 | 别临时加写 |

| 演进 | 按需拆分 | 别过度设计 |

练习题

练 1:设计下单时"预占库存"的 SQL,要求库存不足时不成功。

<details>

<summary>参考答案</summary>

UPDATE t_sku_stock
SET locked = locked + 1, update_time = NOW()
WHERE sku_id = 66 AND (stock - locked) >= 1;

可用库存 = stock - locked,条件保证不超卖;受影响 0 行即库存不足。支付成功后将 locked 转为实扣,超时/取消则 locked 减回。

</details>

练 2:商品改价后,老订单显示的价格被联动改了,问题出在哪?怎么修?

<details>

<summary>参考答案</summary>

订单明细没有做价格快照,而是实时联商品表取现价。修复:在订单明细表冗余下单时的商品名称、单价、规格,后续商品改价/下架不影响历史订单;老数据批量回填一次快照。

</details>

下一篇预告:第 34 章 百度华为系MySQL真题精讲

— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 33 章 京东系MySQL真题精讲》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。