应存session(未登录时)和数据库(登录后),tp5商城采用双写策略:游客用session存储,登录后同步至数据库并自动合并,避免刷新丢数据。

购物车数据该存在 session 还是数据库?
TP5 商城里,未登录用户购物车必须用 session 存,登录后建议同步到数据库并保持双写(登录态切换时自动合并)。硬切到数据库会导致游客加购失败、页面刷新丢数据——这是最常被忽略的起点。
实操建议:
- 游客阶段统一走
$this->request->session()->set('cart', $data),不要碰数据库 - 用户登录成功后,立即调用合并逻辑:把
session里的商品逐条查重,INSERT ... ON DUPLICATE KEY UPDATE写入user_cart表(主键设为user_id + goods_id + spec_key) - 后续所有接口优先读数据库(含未登录请求?不,要加判断:没
user_id就 fallback 到session)
怎么处理 SKU 规格选择导致的重复加购?
用户选「黑色 / XL」加一次,再选「黑色 / L」又加一次,结果生成两条记录——这不是 bug,是正确行为。但很多人误用 goods_id 做唯一标识,导致规格覆盖。
关键在规格编码设计:
- 后端拼接规格标识必须稳定可逆,推荐用
md5(implode('_', $spec_ids))或直接存spec_ids数组 JSON 字符串(如"[101,205]"),别用中文名 - 加购前查重条件是:
WHERE user_id = ? AND goods_id = ? AND spec_key = ?,不是只看goods_id -
spec_key字段建联合索引:(user_id, goods_id, spec_key),否则并发加购可能产生脏数据
TP5 的 validate 验证器怎么防无效 cart 操作?
前端传个 {"goods_id":"abc","num":"-5"},不拦住就会写坏数据。TP5 的 Validate 要覆盖三类校验:
-
goods_id必须是正整数且存在于goods表(用checkGoodsExists自定义规则) -
num必须是between:1,999,不能是字符串或负数 -
spec_key若非空,需匹配该商品已启用的规格组合(查goods_spec_value表验证)
示例规则片段:
[ 'goods_id' => 'require|number|gt:0', 'num' => 'require|number|between:1,999', 'spec_key' => 'alphaNum|max:64' ]
清空购物车时 delete 操作为什么慢?
用户点“清空”,执行 Db::name('user_cart')->where('user_id', $uid)->delete(),看着简单,但线上可能卡顿。原因常是没索引或大表锁表。
两个必须动作:
- 确保
user_cart.user_id有单列索引(TP5 迁移时容易漏) - 高并发场景改用软删:把
status字段设为tinyint,清空只更新status = 0,查购物车时加WHERE status = 1 - 如果真要物理删,避免在事务里连带删关联日志表——购物车清空不该触发订单快照生成
规格组合多、用户量上来后,user_cart 表会成为热点,这时候 session+数据库双写策略的价值才真正体现出来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











