真实商城必须用 redis 而非 session,因 session 不支持多实例部署和跨请求共享;redis 仅存轻量 cart_id→map[string]*cartitem,商品详情查库获取,key 为 "cart:{user_id}" 并设 7 天过期。

Beego 中购物车数据该存在 session 还是 Redis?
直接存 session 最快上手,但不支持多实例部署和跨请求共享;真实商城必须用 Redis。Beego 本身不内置 Redis 客户端,得自己集成 github.com/go-redis/redis/v8 或 gopkg.in/redis.v5(注意 v5 更兼容 Beego 1.x)。
关键点:不要把整个购物车结构(比如含商品详情)全塞进 Redis,只存 cart_id → map[string]*CartItem,其中 string 是商品 SKU ID,*CartItem 只含 quantity、selected 等轻量字段。商品名称、价格等查库或调商品服务获取。
- session 方案仅适合本地调试,
beego.BConfig.WebConfig.Session.SessionProvider = "memory"启动后重启即丢数据 - Redis key 建议用
"cart:{user_id}"格式,避免 key 冲突;设置过期时间(如 7 天),用client.Set(ctx, key, data, 7*24*time.Hour) - 别在 Controller 里反复 new Redis client,用 Beego 的
AppConfig初始化一次,挂到beego.AppConfig或全局变量
添加商品时如何防止超库存和重复加购?
加购不是简单 cart[sku]++,必须查库存、校验状态、再原子更新。Beego 没有事务封装,得手动控制顺序。
典型流程:先查商品表确认 status=1 且 stock >= quantity;再读当前购物车中该 SKU 数量;最后用 Redis 的 HINCRBY(哈希增量)或 Lua 脚本保证“读-判-写”原子性。单纯用 GET + SET 在并发下会超卖。
- 前端传来的
quantity必须做服务端校验:if qty 99直接拒绝 - SKU 字段必须严格校验格式(如正则
^[a-zA-Z0-9_-]{6,32}$),防注入或误操作 - Beego 的
this.Ctx.Input.RequestBody默认不自动解析 JSON body,记得在router.go加beego.InsertFilter("/api/cart/*", beego.BEFORE_ROUTER, filters.JSONBodyFilter)
Beego Controller 里怎么组织购物车增删改查逻辑?
别把所有逻辑堆在 CartController.Add() 里。拆出 cart.Service 层,接收 context.Context、user_id、sku 等参数,返回 error 和新数量。Controller 只负责参数提取、错误转 HTTP 状态码、日志打点。
例如 Add 方法内部要调三次外部依赖:查商品(DB 或 RPC)、查当前购物车数量(Redis)、扣减库存(DB 更新或发消息)。任一失败都要回滚前序动作——Redis 写了但 DB 扣失败?得立刻 DEL 或 HDEL 对应字段。
- 所有外部调用必须设超时:
ctx, cancel := context.WithTimeout(r.Context(), 800*time.Millisecond) - Beego 的
this.Data["json"]返回 JSON 前,确保结构体字段都加json:"xxx"tag,否则返回空对象 - 删除商品用
DEL cart:{user_id}是错的——会清空整个购物车;正确是HDEL cart:{user_id} {sku}或 Lua 脚本精准剔除
为什么 Beego 的 ORM 关联查询不适合购物车商品列表?
购物车列表要展示商品图、名称、价格、库存状态,但这些字段分散在商品主表、SKU 表、库存表。Beego ORM 的 LoadRelated 会 N+1 查询,10 个商品可能触发 30+ SQL,拖慢接口。
正确做法是:用原生 SQL 或 raw 查询一次性 JOIN 获取全部所需字段,再用 map[string]interface{} 或自定义 struct Scan。或者更推荐——购物车只存 SKU ID,列表页由前端或网关层聚合调用商品中心接口,后端购物车模块保持职责单一。
- Beego ORM 的
QueryTable("cart_item").RelatedSel("product").All(&items)在高并发下容易打爆数据库连接池 - 如果坚持用 ORM,至少把购物车项表设计为宽表,冗余
price、title字段(下单时快照),但需同步机制防脏读 - 测试时用
beego.TestBeegoInit()启动 mock Redis 和 DB,别依赖真实环境











