核心概念与区别总览
| 方法 | 核心用途 | 使用场景 | 返回值 |
| Find | 查询并直接填充模型 / 切片 | 常规的 ORM 风格查询(查结构体 / 切片) | *gorm.DB |
| Raw | 执行原生 SQL,返回可扫描的结果集 | 复杂 SQL(联表、函数、自定义排序) | *gorm.DB |
| Row | 获取单条原生 SQL 的行结果 | 原生 SQL 查单条记录,手动解析字段 | *sql.Row |
| Scan | 将查询结果映射到变量 / 结构体 | 配合 Raw/Row/Find 解析结果 | error |
| Exec | 执行无返回结果的 SQL(写操作) | 增 / 删 / 改、执行存储过程、DDL 语句 | *gorm.DB(含 RowsAffected) |
逐个拆解(附代码示例)
(1)Find:ORM 风格的查询(最常用)
- 核心:GORM 最基础的查询方法,直接将查询结果填充到结构体 / 切片中,完全封装了 SQL 细节。
- 特点:面向模型(Model),自动映射字段,支持链式调用(Where/Order/Limit 等)。
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 定义模型
type User struct {
ID uint
Name string
Age int
}
func main() {
db, _ := gorm.Open(mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"), &gorm.Config{})
// 示例1:查询所有用户(填充到切片)
var users []User
db.Find(&users) // 等价于 SELECT * FROM users;
// users 会被填充为所有用户的列表
// 示例2:条件查询
var user User
db.Where("id = ?", 1).Find(&user) // 等价于 SELECT * FROM users WHERE id = 1;
// user 会被填充为 id=1 的用户
}
(2)Raw:执行原生 SQL(复杂查询)
- 核心:直接执行手写的原生 SQL,返回 *gorm.DB,需要配合 Scan 解析结果到变量 / 结构体。
- 特点:突破 ORM 限制,支持联表、聚合函数、复杂子查询等。
func main() {
db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
// 示例:原生 SQL 查询(联表)
var result struct {
UserName string
OrderID uint
}
// 执行原生 SQL,用 Scan 解析结果
db.Raw("SELECT u.name, o.id FROM users u JOIN orders o ON u.id = o.user_id WHERE u.id = ?", 1).Scan(&result)
// 批量结果解析到切片
var results []struct{UserName string; OrderID uint}
db.Raw("SELECT u.name, o.id FROM users u JOIN orders o ON u.id = o.user_id").Scan(&results)
}
(3)Row:获取原生 SQL 的单行结果
- 核心:是 Raw 的 “轻量版”,专门用于获取单条原生 SQL 结果,返回 *sql.Row(标准库类型),需手动调用 Scan 解析字段。
- 特点:更贴近数据库驱动层,适合只需要少数字段的场景。
func main() {
db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
// 示例:Row 获取单行结果
row := db.Table("users").Where("id = ?", 1).Row() // 等价于 SELECT * FROM users WHERE id = 1 LIMIT 1;
var name string
var age int
// 手动 Scan 到指定变量(字段顺序要和查询结果一致)
err := row.Scan(&name, &age)
if err != nil {
// 处理错误
}
}
(4)Scan:结果映射工具(配合查询方法)
- 核心:不是独立的查询方法,而是解析查询结果的工具 —— 将 Find/Raw/Row 的查询结果映射到变量 / 结构体 / 切片。
- 特点:是 “桥梁”,无查询能力,仅负责数据解析。
func main() {
db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
// 示例1:配合 Find 使用(解析部分字段)
var names []string
db.Model(&User{}).Select("name").Where("age > ?", 18).Scan(&names) // 只查 name 字段,填充到字符串切片
// 示例2:配合 Raw 使用(解析到结构体)
var user User
db.Raw("SELECT id, name FROM users WHERE id = ?", 1).Scan(&user)
}
(5)Exec:执行无返回结果的 SQL(写操作)
- 核心:执行不返回数据行的 SQL 语句(增 / 删 / 改、DDL、存储过程等),返回 *gorm.DB,可通过 RowsAffected() 获取受影响的行数。
- 特点:不处理查询结果,仅关注执行结果(成功 / 失败、受影响行数)。
func main() {
db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
// 示例1:更新操作
result := db.Exec("UPDATE users SET age = ? WHERE id = ?", 20, 1)
// 获取受影响的行数
rowsAffected, _ := result.RowsAffected()
// 检查是否执行失败
if result.Error != nil {
// 处理错误
}
// 示例2:删除操作
db.Exec("DELETE FROM users WHERE age < ?", 18)
// 示例3:DDL 语句(创建表)
db.Exec("CREATE TABLE IF NOT EXISTS logs (id INT PRIMARY KEY AUTO_INCREMENT, content TEXT)")
}
总结
核心选择逻辑:简单查询用 Find,复杂 SQL 用 Raw,单行原生结果用 Row,写操作 / DDL 用 Exec,解析结果统一用 Scan。

