Beego ORM 的 SQL 调试日志需显式设置 orm.Debug = true(注册数据库后、查询前),仅影响标准 ORM 操作,不记录 Raw 语句;常见失效原因包括设置时机错误、Raw 调用未 Prepare、goroutine 隔离及 stdout 重定向。

Beego ORM 的 SQL 调试日志不是靠“开启某个开关”就自动打印所有语句的,必须在注册数据库后、执行查询前显式设置 orm.Debug = true,且该设置只对当前进程有效,重启即失效。
为什么开了 orm.Debug 却看不到 SQL?
常见原因有三个:
-
orm.Debug = true写在了orm.RegisterDataBase之前 —— 此时 ORM 尚未初始化,赋值无效 - 用了
o := orm.NewOrm()后又调用o.Raw(...).Exec(),但Raw默认不走调试日志逻辑,需额外加.Prepare()或改用o.QueryTable().Filter().All()等标准链式调用 - 项目用了多模块或子 goroutine 初始化(比如在 controller init 中设置),而实际查询发生在另一个 goroutine,
Debug是全局变量,但日志输出可能被重定向或缓冲未刷出
orm.Debug = true 的真实行为和限制
它只影响 ORM 自动生成的 SQL(如 Insert、Update、QueryTable().All()),不拦截 Raw 执行的原生语句,也不打印参数绑定值。输出格式类似:
INSERT INTO `user` (`name`, `age`) VALUES (?, ?); args: [alice 28]
注意:
- 日志输出到
os.Stdout,若项目用了自定义 logger(如 beego logs),需确保 stdout 未被关闭或重定向 - 生产环境绝对不能留着
orm.Debug = true,不仅暴露表结构,还拖慢性能(每条 SQL 都要格式化+输出) - MySQL 连接字符串里必须带
parseTime=true,否则time.Time字段的 SQL 参数会变成空字符串,日志里看到的是args: ["" 28]
替代方案:用 Raw + Prepare 查看完整 SQL
当 orm.Debug 不够用(比如想确认 JOIN 条件或嵌套查询生成的语句),可临时改用 Raw 搭配 Prepare 手动拼 SQL:
sql := `SELECT u.name, p.title FROM user u JOIN post p ON u.id = p.user_id WHERE u.id = ?` o := orm.NewOrm() stmt, _ := o.Raw(sql, 123).Prepare() // 此时 stmt.SQL() 返回已替换参数的完整语句(仅调试用,勿用于生产) fmt.Println(stmt.SQL()) // 输出:SELECT u.name, p.title FROM user u JOIN post p ON u.id = p.user_id WHERE u.id = 123
这个技巧的关键点:
-
Prepare()是Raw对象的方法,不是o的方法 -
stmt.SQL()返回的是**已插值**的字符串,不是带问号的模板 - 仅限调试,因为插值由 Go 完成,绕过了数据库预编译,有 SQL 注入风险
真正难的不是打开日志,而是理解哪些操作会被记录、哪些不会,以及日志里缺失的上下文(比如事务边界、连接池状态)——这些得靠 o.Begin() + defer o.Commit() 显式标注,而不是依赖日志自动推断。











