★ GoFrame 常见坑(ctx 首参、指针接收、时区等)
面试问法:用 GoFrame 开发时你踩过哪些坑?怎么避免? 一句话结论:高频坑集中在五类——ctx 没有作为首参贯穿、do/entity/dao 模型混用、时区与 gtime/time.Time 混用、事务内没用对连接、以及路由/校验对结构体的隐式约定。多数坑都能靠“遵守官方分层与签名约定”规避。
高频坑清单
- ctx 不贯穿:dao、日志、链路追踪都需要带 ctx;漏传会导致事务/追踪信息丢失。约定:controller → service → dao 每个方法首参都是 ctx。
- 模型混用:读数据用
entity、写与条件构造用do(指针表达“未设置”),把 do 当 entity 扫描或反之都容易出错。 - 时区:连接串不带
loc=Local&parseTime=true、或time.Parse得到 UTC 时间,条件查询偏差 8 小时(见 gtime 章节)。 - gtime 与 time.Time 混用:JSON 序列化格式不同(gtime 输出
2006-01-02 15:04:05),接口层与持久层类型要保持一致。 - 事务内仍用不带事务的 dao:事务要在
g.DB().Transaction回调内用回调 ctx / tx 操作,事务外查询不会自动加入事务。 - 结构体约定破坏:规范路由 handler 必须
(ctx, req) (res, err)签名、Req/Res 命名带后缀,否则路由注册或参数绑定异常。 - 校验与 JSON 标签顺序:
v规则与字段顺序、bail修饰影响失败即停;含required规则建议放最前。 - 分层循环依赖:controller 依赖 service、service 依赖 dao 是单向的;api 结构体独立成包,避免 api ↔ internal 互相 import。
- 生产开着 debug:SQL 全量打印 + 堆栈,性能断崖;部署前检查
database.default.debug: false。 - Model 对象复用:带链式状态的 Model 跨请求/跨 goroutine 复用有竞态,每个请求从
dao.Xxx.Ctx(ctx)现取。
两个典型代码对比
// 坑:事务外自建连接、丢了 ctx
g.DB().Model("user").Data(g.Map{"name": "a"}).Insert() // 不在事务内
// 正:事务回调内操作(tx 或回调 ctx 传入的 dao 用法以官方文档为准)
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 使用事务对象或按官方文档经 ctx 绑定事务的 dao 写法
return nil
})
// 坑:time.Parse 得到 UTC,入库/比较偏 8 小时
t, _ := time.Parse("2006-01-02 15:04:05", "2024-01-02 10:00:00")
// 正:用本地时区解析
t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2024-01-02 10:00:00", time.Local)
常见追问
- 追问:异步 goroutine 里能用请求的 r 对象吗?——不能;请求结束对象会被框架回收复用,只把 ctx(或必要值)传出去。
- 追问:SetTimeZone 为什么有时不生效?——标准库 time 在 import 初始化时会固定时区;要把设置放独立包并在 main 最前面空导入,否则只能对对象逐个 ToLocation。
记忆点
- 三守则:ctx 首参贯穿、类型用对(entity/do/gtime)、约定别破坏(分层、签名、时区)。