Go GORM 完整使用教程(对比原生 SQL) 一、原生 database/sql 基础回顾 1. 初始化数据库连接 go
运行
1 2 3 4 5 6 7 8 9 import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) // DSN格式:用户名:密码@tcp(IP:端口)/数据库名 dsn := "root:root@tcp(127.0.0.1:3306)/dorm" db, err := sql.Open("mysql", dsn)
2. 连通性校验 go
运行
1 2 3 4 5 err = db.Ping() if err != nil { panic("数据库连接失败") }
3. DML 操作(增删改) 使用 Exec(),返回受影响行数、自增 ID
go
运行
1 2 res, err := db.Exec("INSERT INTO user(name) VALUES(?)", "张三")
4. DQL 查询操作 (1)多行查询 Query () + 循环 Scan go
运行
1 2 3 4 5 6 7 8 9 rows, err := db.Query("SELECT id,name FROM user WHERE id > ?", 1) defer rows.Close() for rows.Next() { var id int var name string err = rows.Scan(&id, &name) }
(2)单行查询 QueryRow ().Scan () go
运行
1 2 3 var name string err := db.QueryRow("SELECT name FROM user WHERE id=?", 1).Scan(&name)
二、GORM 初始化全局 DB 实例 1. 依赖安装 bash
运行
1 2 3 go get gorm.io/gorm go get gorm.io/driver/mysql
2. 全局 DB 变量 + 连接初始化函数 go
运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import ( "gorm.io/driver/mysql" "gorm.io/gorm" ) // 全局DB,项目全局调用 var DB *gorm.DB func ConnectMysql() { dsn := "root:123456@tcp(127.0.0.1:3306)/gorm_study" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("GORM连接数据库失败:" + err.Error()) } DB = db }
三、数据表自动迁移 AutoMigrate 无需手动建表,根据 Model 结构体自动创建 / 更新表结构
go
运行
1 2 3 4 5 6 7 8 9 10 11 12 13 import "你的项目/global" import "你的项目/model" func MigrateTable() { // 无表自动创建,字段变更自动新增列,不会删除原有列 err := global.DB.AutoMigrate(&model.UserModel{}) if err != nil { fmt.Println("迁移失败", err) return } fmt.Println("数据表迁移成功") }
四、单表 CRUD 操作 前置 Model 示例 go
运行
1 2 3 4 5 6 7 8 import "gorm.io/gorm" type UserModel struct { gorm.Model // 内置ID、CreatedAt、UpdatedAt、DeletedAt(软删除) Name string Age int }
1. 新增 Create go
运行
1 2 3 4 5 user := UserModel{Name: "张三", Age: 20} // 单条插入 err := global.DB.Create(&user).Error // user.ID 会自动回填自增主键
2. 查询操作(核心方法对比) 表格
方法
接收变量
返回数据量
默认排序
无数据返回
First
单个结构体
1 条
主键升序 LIMIT 1
报错 gorm.ErrRecordNotFound
Find
结构体切片
多条 / 全部
无默认排序
返回空切片,无错误
多条件分页、排序查询 go
运行
1 2 3 4 var userList []UserModel // Where条件 + 倒序 + 限制条数 global.DB.Where("age = ?", 100).Order("id DESC").Limit(3).Find(&userList)
常用链式调用说明
Where():拼接查询条件,不执行 SQL
Order():排序规则
Limit():限制返回行数
Offset():偏移量,配合 Limit 实现分页
3. 更新操作 Update / Updates 更新单个字段 go
运行
1 2 3 // id=1的用户,age更新为25 err := global.DB.Model(&UserModel{}).Where("id = ?", 1).Update("age", 25).Error
更新多个字段(结构体 / Map) go
运行
1 2 3 4 5 6 7 8 9 10 11 // 方式1:结构体 u := UserModel{Name: "李四", Age: 28} err := global.DB.Model(&UserModel{}).Where("id = ?", 2).Updates(u).Error // 方式2:map(推荐,零值也会更新) updateData := map[string]any{ "name": "王五", "age": 30, } global.DB.Model(&UserModel{}).Where("id=?", 3).Updates(updateData)
4. 删除操作(软删除 / 真实删除) 前提:开启软删除 结构体嵌入 gorm.Model 自带 DeletedAt,GORM 默认实现软删除(UPDATE 标记删除,不物理 DELETE)
(1)软删除 go
运行
1 2 3 4 5 6 7 // 单条删除(根据主键) user := UserModel{ID: 2} err := global.DB.Delete(&user).Error // 批量条件删除 err := global.DB.Model(&UserModel{}).Where("age = ?", 10).Delete(&UserModel{}).Error
(2)物理真实删除 Unscoped () go
运行
1 2 3 4 5 6 7 // 单条真删 user := UserModel{ID: 3} global.DB.Unscoped().Delete(&user) // 批量条件真删 global.DB.Unscoped().Model(&UserModel{}).Where("age < ?", 18).Delete(&UserModel{})
五、Select / Scan / Pluck 专用查询 1. Select:指定查询列 go
运行
1 2 3 4 var user UserModel // 只查询name、age两列 global.DB.Select("name,age").Where("id=?", 1).Find(&user)
2. Scan:自定义变量接收结果(脱离 Model 绑定) 适合统计 count、自定义字段映射
go
运行
1 2 3 4 5 var total int64 // 统计成年用户总数 err := global.DB.Model(&UserModel{}).Where("age > ?", 18). Select("count(*)").Scan(&total).Error
3. Pluck:单独提取某一列到切片 无需完整结构体,批量拿单列数据
go
运行
1 2 3 4 var ids []uint // 批量取出所有成年用户id global.DB.Model(&UserModel{}).Where("age >= ?", 20).Pluck("id", &ids)
六、Scope 复用查询条件(封装通用逻辑) 把重复的 Where/Order 封装成函数,多处复用,统一维护条件
1. 定义 Scope 函数 go
运行
1 2 3 4 5 // 封装:只查询成年用户 func AdultUserScope(db *gorm.DB) *gorm.DB { return db.Where("age >= ?", 18) }
2. 调用 Scope go
运行
1 2 3 4 var list []UserModel // 复用通用条件,再叠加自定义排序 global.DB.Scopes(AdultUserScope).Order("id DESC").Find(&list)
七、GORM 执行原生 SQL 1. 查询 SQL Raw () + Scan 占位符?防 SQL 注入,禁止字符串拼接
go
运行
1 2 3 4 5 6 7 8 9 // 统计总数 var cnt int64 err := global.DB.Raw("SELECT COUNT(*) FROM user_model WHERE age >= ?", 18).Scan(&cnt).Error // 多行查询映射结构体 var userList []UserModel sql := "SELECT * FROM user_model WHERE age > ? ORDER BY id DESC LIMIT ?" err := global.DB.Raw(sql, 18, 10).Scan(&userList).Error
2. 增删改 SQL Exec () go
运行
1 2 3 4 5 6 7 sql := "INSERT INTO user_model(name,age,created_at,updated_at) VALUES (?,?,NOW(),NOW())" res, err := global.DB.Exec(sql, "小王", 22) // 获取自增主键、受影响行数 lastID, _ := res.LastInsertId() rowsAffected, _ := res.RowsAffected()
八、多表关联关系(一对一演示) 1. Model 结构示例 go
运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 用户主表 type UserModel struct { gorm.Model Name string Age int UserDetail UserDetailModel // 一对一关联 } // 用户详情附表 type UserDetailModel struct { gorm.Model Phone string UserID uint // 外键关联user.id }
2. 预加载 Preload 关联查询 正向查询(查详情,带出所属用户) go
运行
1 2 3 var detail UserDetailModel global.DB.Preload("UserModel").Take(&detail, "user_id=?", 15)
反向查询(查用户,带出详情) go
运行
1 2 3 var user UserModel global.DB.Preload("UserDetailModel").Take(&user, 15)
3. 级联删除 可在 Model 关联标签配置级联删除,删除主表数据时自动删除关联附表数据,无需手动操作多条 DELETE