Golang怎么用GORM原生SQL查询_Golang如何用Raw执行自定义SQL语句【方法】

2次阅读

Raw() 返回的 *gorm.DB 需链式调用 Scan()/Find()/Rows() 才执行;参数用? 占位;Scan 目标须导出且类型匹配;不触发钩子、软删除、Preload 等 GORM 特性。

Golang 怎么用 GORM 原生 SQL 查询_Golang 如何用 Raw 执行自定义 SQL 语句【方法】

Raw() 返回的 *gorm.DB 不能直接用 Scan()

很多人写 db.Raw("SELECT name FROM users").Scan(&name) 报错,因为 Raw() 返回的是一个未执行的查询构建器,不是结果集。它得先调用 Scan()Find()Rows() 才真正发请求。

  • Raw() 只拼 SQL,不执行;必须链式调用 Scan()(结构体 / 变量)或 Rows()(获取 *sql.Rows)才能触发执行
  • 如果只想要单个值(比如 count),用 Count() 更安全,避免 Scan 类型不匹配
  • Scan() 时,目标变量类型必须和 SELECT 字段严格对应:SELECT 两个字段就得扫进有两个字段的 struct 或两个变量的 slice

参数绑定要用 ? 而不是 $1 或 :name

GORM 的 Raw() 默认使用数据库驱动原生占位符,MySQL/SQLite 用 ?,PostgreSQL 默认也走 ?(除非显式启用 WithClause(clause.SQL{SQL: "……"}) 或改配置)。写成 $1:name 在大多数情况下直接报 sql: expected 0 arguments, got 1 或语法错误。

  • 正确写法:db.Raw("SELECT * FROM users WHERE id > ?", minID).Find(&users)
  • 多个参数按顺序填入:db.Raw("SELECT * FROM orders WHERE status = ? AND created_at > ?", "paid", time.Now().AddDate(0,0,-7))
  • 想用命名参数?GORM 不原生支持;可手动拼接(不推荐,注意 SQL 注入),或改用 Session(&gorm.Session{PrepareStmt: true}) + 驱动层支持(如 pgx 对 PostgreSQL 的 $1 支持需额外配置)

Scan 到 struct 时字段名必须匹配,且 struct 要有公开字段

常见错误是 struct 字段没加导出(首字母大写),或者 json:/gorm: tag 写错导致映射失败,结果扫出来全是零值,还不报错。

  • struct 字段必须是公开的(首字母大写),否则 GORM 无法反射赋值
  • 字段名默认按蛇形转驼峰匹配(user_nameUserName),但若字段名含大小写混合(如 APIKey),对应数据库列应为 api_key;不一致就加 gorm:"column:api_key"
  • 如果 SELECT 的列名和 struct 字段完全不相关(比如用了 AS 别名),必须确保别名符合驼峰规则,或改用 map[string]interface{} 接收再手动转

Raw 查询不走 GORM 钩子和关联预加载

这是最容易被忽略的点:你写了 BeforeCreate 钩子、启用了软删除、甚至配了 Preload("Profile"),但 Raw() 一上,全失效。它绕过 GORM 的整个模型层,直连 *sql.DB

立即学习 go 语言免费学习笔记(深入)”;

  • 软删除字段(deleted_at)不会自动加到 WHERE 条件里
  • TableName() 方法、gorm.Model(&u) 指定的表名也不会生效,得自己写进 SQL 字符串
  • 事务内执行没问题,但关联数据得自己 JOIN 或额外查,PreloadJoinsRaw() 无效
  • 如果只是想加点条件或排序,优先考虑用 GORM 链式方法(Where()Order()),而不是急着切 Raw

GORM 的 Raw() 是逃生舱,不是驾驶舱。它快、灵活,但也意味着你得自己扛字段映射、参数安全、生命周期管理——尤其当项目开始加审计字段、租户隔离、动态 schema 时,裸 SQL 很容易漏掉一层过滤。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-20发表,共计1563字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources