前言
在使用 GORM 开发 Go 项目时,经常需要查看实际执行的 SQL 语句------排查慢查询、调试数据逻辑、确认查询条件是否正确......但 GORM 默认是关闭的,不会主动把 SQL 打印出来。
方式一:全局开启 Debug 模式(最简单)
GORM 提供了一个非常方便的方法------db.Debug(),它会把所有 SQL 语句打印到标准输出,包括执行的 SQL、影响的行数和耗时。
只需一行代码:
go
db = db.Debug()
之后所有的查询都会打印 SQL,例如:
[0.23ms] [rows:1] SELECT * FROM `users` WHERE `id` = 1
适合场景: 开发环境整体调试,想看全局 SQL 的情况。
实际项目中怎么做? 通常会用一个环境变量来控制。初始化数据库连接时:
go
func InitDB() {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if os.Getenv("DEBUG") == "true" {
db = db.Debug() // 只有 DEBUG=true 时才开启
}
DB = db
}
启动服务时加上环境变量即可:
bash
DEBUG=true ./my-app
这样生产环境不会误打印,开发环境一键开启,非常灵活。
方式二:单条查询临时 Debug(最精准)
如果全局打印太多,你只想看某一条 SQL,可以在查询链上临时加 .Debug():
go
// 只打印这条查询的 SQL
db.Debug().Where("status = ?", 1).Find(&users)
// 其他查询不受影响
db.Where("role = ?", "admin").Find(&admins) // 这条不会打印
适合场景: 只想排查某个特定查询,不想被大量日志淹没。
这种方式非常轻量,不需要改任何配置,用完把 .Debug() 删掉就行。
方式三:自定义 Logger(最专业)
如果你需要更精细的控制------比如只想打印慢查询、想把 SQL 写到文件而不是终端、想在日志中加上请求ID等上下文------就需要自定义 GORM 的 Logger。
go
import (
"log"
"os"
"time"
"gorm.io/gorm/logger"
)
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: 200 * time.Millisecond, // 慢查询阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略 ErrRecordNotFound
Colorful: true, // 彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
关键参数解释:
| 参数 | 作用 |
|---|---|
SlowThreshold |
超过这个时间的查询会被标记为慢查询,单独警示 |
LogLevel |
Silent 不打印、Error 只打印错误、Warn 打印错误+慢查询、Info 打印所有 |
IgnoreRecordNotFoundError |
是否忽略 "记录未找到" 这种常见错误(避免日志刷屏) |
Colorful |
终端输出是否带颜色,方便区分不同级别 |
适合场景: 生产环境监控、慢查询分析、日志持久化到文件等进阶需求。
三种方式对比
| 方式 | 影响范围 | 使用难度 | 适用场景 |
|---|---|---|---|
全局 db.Debug() |
所有 SQL | ★☆☆ | 开发环境整体调试 |
单条 .Debug() |
仅该条查询 | ★☆☆ | 临时排查某条查询 |
| 自定义 Logger | 可精细控制 | ★★★ | 生产环境/慢查询监控 |
小结
日常开发中,方式一 + 方式二 就够用了:全局 Debug 看整体,单条 Debug 看细节。当你需要上生产环境做监控时,再考虑方式三自定义 Logger。