Raw查询必须调用QueryRow或Values才能执行,仅Raw()只构造RawSeter;占位符仅支持?;映射struct需字段名或orm tag严格匹配;JOIN慎用QueryRow,优先分步查。

Raw 查询必须用 QueryRow 或 Values,不能只调 Raw()
很多人写完 orm.Raw("SELECT * FROM user WHERE id = ?", 123) 就以为查到了数据,其实这只是构造了一个 RawSeter,还没真正执行 SQL。不调用后续方法,数据库压根不会响。常见错误是直接打印这个对象,结果看到空值或 panic。
-
QueryRow(&v):查单行,必须传入地址,且结构体字段名/类型要和 SELECT 字段顺序、类型严格匹配(比如id int64对应数据库BIGINT) -
Values(&list):查多行,list是[]orm.Params类型,返回的是 map[string]interface{} 切片,字段名全小写,适合快速取数、不做强类型绑定的场景 - 别用
Exec()执行 SELECT —— 它会报错:ERROR: query has no destination,因为Exec只处理影响行数的操作(INSERT/UPDATE/DELETE)
Raw 占位符只支持 ?,不支持命名参数
Beego ORM 的 Raw 不识别 :id 或 $1 这类命名占位符,所有参数都靠 ? 顺序填充。PostgreSQL 用户尤其容易踩坑:即使驱动本身支持 $1,Beego 这层封装也强制转成 ? 再交给底层 driver。
- 正确写法:
o.Raw("SELECT name FROM user WHERE status = ? AND created_at > ?", "active", time.Now().AddDate(0,0,-7)) - 错误写法:
o.Raw("SELECT name FROM user WHERE status = $1", "active")→ 参数不被识别,SQL 报错或查出空结果 - 如果 SQL 很长、参数多,建议先用
fmt.Sprintf拼好语句再调试,但上线前务必换回?占位,避免 SQL 注入
查询结果映射到 struct 时,字段名大小写和 tag 必须对齐
用 QueryRow 或 ValuesScan 映射到自定义 struct 时,Beego 不自动做 snake_case ↔ camelCase 转换。数据库字段 user_name 默认不会塞进 struct 的 UserName 字段里,除非显式声明 tag。
- 结构体要加
ormtag:UserName string `orm:"column(user_name)"` - 如果没写 tag,字段名必须和 SELECT 出来的列名完全一致(包括大小写),例如
SELECT user_name AS user_name→ struct 字段得叫user_name(小写下划线) - 用
Values返回[]orm.Params可绕过这个问题,但 lose 了类型安全和 IDE 提示
复杂 JOIN 查询慎用 Raw + QueryRow,优先考虑分步查
当原生 SQL 包含多表 JOIN(比如 user LEFT JOIN profile ON user.id = profile.user_id),QueryRow 映射 struct 容易 panic:字段重复、类型冲突、空值无法赋给非指针字段。ORM 不会帮你做字段去重或智能解包。
- 简单方案:用
Values拿 map 切片,自己挑 key 赋值 - 稳健方案:拆成两个查询,先查主表 ID,再用
In()查关联数据,配合内存缓存减少 DB 压力 - 如果真要用 JOIN,确保 SELECT 显式列出所有字段并起别名(
user.id AS u_id, profile.age AS p_age),struct 字段名严格对应别名
实际执行原生查询这件事,最难的不是写 SQL,而是让结果稳稳落到变量里——字段名、占位符、类型、空值处理,每一步漏掉一个细节,就卡在 silent fail 上。别迷信“查到了”,一定要检查 err 和返回长度。











