tosql() 在 gorm v2 中被彻底移除,调用会报错;v1 版本虽保留但已停止维护。v2 推荐用 debug() 查看 sql,或 dryrun + statement.sql.string() 与 vars 手动拼接,但需注意参数安全与插件影响。

为什么 ToSQL() 在新版本 GORM 中不可用
因为 GORM v2(gorm.io/gorm)彻底移除了 ToSQL() 方法。它不是被隐藏或改名,而是从 API 中删除了——调用会直接报错 undefined method ToSQL。老项目如果还用着 GORM v1(github.com/jinzhu/gorm),虽然有这个方法,但 v1 已停止维护,不建议继续使用。
GORM v2 获取 SQL 的正确方式:用 Session + Debug()
最简单、最贴近开发调试需求的方式是启用调试模式,让 GORM 把生成的 SQL 和参数一起打印到 stdout 或自定义日志器。这不是“取字符串”,但能 100% 看到最终执行的语句。
常见做法:
- 开发环境直接加
.Debug():比如db.Debug().First(&user),控制台立刻输出类似SELECT * FROM "users" WHERE "users"."id" = 1的完整 SQL - 想捕获 SQL 字符串而非打印?得绕一层:用
db.Session(&gorm.Session{DryRun: true})搭配Statement解析 -
DryRun: true不真正查询,只构建语句并填充参数,但注意:它不会展开IN (?)这类占位符,参数仍以[]interface{}形式存在
手动拼出可执行 SQL 字符串(含参数值)的可靠做法
需要把 ?/ 替换成真实值(比如用于审计、日志归档或 DBA 审核),不能只靠 DryRun。必须自己做参数替换,且要注意类型安全和 SQL 注入风险——GORM 不提供“带值的 SQL 字符串”导出接口,这是有意为之的安全设计。
实操建议:
- 用
db.Session(&gorm.Session{DryRun: true}).Where("id = ?", 123).Find(&u)触发构建,再从db.Statement.SQL.String()取原始 SQL(含?) - 从
db.Statement.Vars拿参数切片,逐个用driver.Valuer或类型判断转成字符串(例如int64直接fmt.Sprintf("%d", v),string加单引号并转义) - 别用
strings.ReplaceAll简单替换:多个?时顺序必须严格对应Vars,且要考虑nil、time.Time、sql.NullString等特殊值 - 已有成熟小工具可参考:GitHub 上有
gorm/sqlize这类轻量库,本质就是封装了上述逻辑
容易忽略的关键细节
SQL 字符串是否“最终”取决于 GORM 插件链。比如开启 logger.Default 时看到的 SQL,可能已被 soft_delete 或 schema 插件改写过;而 DryRun 模式下,callbacks 仍会执行(如自动添加 WHERE deleted_at IS NULL)。如果你在 hooks 里动态修改了 Statement.SQL,那它才是真正的最终 SQL —— 但这时已经没有通用方法能自动还原参数了。
真要 100% 精确拿到“数据库收到的那条语句”,唯一可靠路径是抓包(如用 tcpdump 或 MySQL 的 general_log),而不是依赖 ORM 层拼接。











