MySQL 本身不直接“实现购物车”,它只负责持久化存储购物车数据;真正的购物车逻辑(比如合并相同商品、库存校验、过期清理)必须由应用层控制。用 MySQL 做购物车,核心是设计好三张表并约束好关系,否则很容易出现重复加购、负库存、脏读等问题。
购物车表结构怎么建才不容易出错
至少需要
users、
products、
cart_items三张表,其中
cart_items是关键中间表:
cart_items.id:主键,自增(不用 UUID,避免插入性能下降)
cart_items.user_id:外键关联
users.id,务必加索引(否则查某人购物车会全表扫描)
cart_items.product_id:外键关联
products.id,也必须加索引
cart_items.quantity:整型,建议设
DEFAULT 1,且加
CHECK (quantity > 0)(MySQL 8.0.16+ 支持) 联合唯一约束:
UNIQUE KEY (user_id, product_id)——这是防止用户重复添加同一商品的关键,不是靠应用层判断
别用单表存 JSON 字段模拟购物车(如
users.cart_json),后期无法走索引、不能原子增减、无法关联商品信息、难以做库存预占。
加购、更新、删商品的 SQL 怎么写才安全
所有操作必须基于
user_id+
product_id组合,避免误改他人购物车或错删商品: 加购(存在则数量+1,不存在则插入):
INSERT INTO cart_items (user_id, product_id, quantity) VALUES (123, 456, 1) ON DUPLICATE KEY UPDATE quantity = quantity + 1;设置指定数量(非累加):
INSERT INTO cart_items (user_id, product_id, quantity) VALUES (123, 456, 3) ON DUPLICATE KEY UPDATE quantity = VALUES(quantity);删单个商品:
DELETE FROM cart_items WHERE user_id = 123 AND product_id = 456;清空购物车:
DELETE FROM cart_items WHERE user_id = 123;
注意:
ON DUPLICATE KEY UPDATE依赖前面说的
(user_id, product_id)唯一约束,没它就退化成普通 INSERT,可能报错或漏更新。
查购物车时为什么总缺商品信息
只查
cart_items表只能拿到 ID 和数量,实际页面要显示商品名、图片、价格,必须 JOIN:
SELECT ci.quantity, p.name, p.price, p.image_url FROM cart_items ci JOIN products p ON ci.product_id = p.id WHERE ci.user_id = 123;
常见错误:
忘了加WHERE ci.user_id = ?,导致查出所有人购物车 用
LEFT JOIN但没处理
p为 NULL 的情况(比如商品已被下架,
products行被删了) 没给
p.id加主键或索引,JOIN 变慢
如果商品信息变更频繁(如价格浮动),建议在
cart_items里冗余快照字段(如
snapshot_price DECIMAL(10,2)),否则下单时价格可能和加购时不一致。
真正难的不是建表或写 SQL,而是把“库存是否足够”“用户是否登录”“商品是否已下架”这些判断塞进事务里,并保证并发加购不超卖——这需要 SELECT ... FOR UPDATE 配合应用层锁或乐观锁,纯靠 MySQL 建表解决不了。
