使用 GORM(Go 的 ORM 库)连接数据库,并实现增删改查操作
前言
面向用户
- 掌握 Go 语言基础
- 了解 MySQL数据库
笔者环境
- macos 10.15.7
- Golang 1.18
- GoLand 2022.01
- Mysql 8.0.20
读完本文可以获得
- 了解ORM框架的定义
- 熟悉使用GORM包进行基本的CRUD
引用
GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
一、介绍
GORM是Go语言的一个ORM(Object Relational Mapping)库。它可以让我们通过Go来操作数据库中的数据。
ORM即对象关系映射,将数据库中的表转为程序中的实体对象(通过建立对象和关系数据之间的映射模型,可以将一个表对应一个实体类;将一条记录对应一个对象。)通过使用面向对象方式来操作数据库,可以简化开发,减少重复劳动。
1.1 特性
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持
Preload
、Joins
的预加载 - 事务,嵌套事务,Save Point,Rollback To Saved Point
- Context,预编译模式,DryRun 模式
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
- 复合主键,索引,约束
- Auto Migration
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus...
- 每个特性都经过了测试的重重考验
- 开发者友好
1.2 使用步骤
- 在MySQL或其他数据库中先创建Schema。
- 使用GORM将Go结构体映射到数据库表,比如定义一个User结构体映射到user表。
- 在Go代码中,我们就可以操作那个结构体,而GORM会在后台自动转换为对应的SQL命令,来crud数据库表中的数据。
- 也可以直接在Go代码中用GORM的API构造SQL查询数据库。
1.3 安装
arduino
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
1.4 导包
在使用GORM连接数据库时,需要导入两个包
- gorm核心库
go
import "gorm.io/gorm"
这个包提供了GORM的核心功能和API。
- 数据库驱动
go
import "gorm.io/driver/mysql"
这个包提供了GORM与MySQL数据库的交互。
GORM 官方支持 sqlite
、mysql
、postgres
、sqlserver
。如果要连接其他类型的数据库,可以复用/自行开发驱动。编写驱动 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
1.5 dsn
dsn(data source name)就是数据库的连接配置信息,包含了连接数据库需要的所有参数。
java
username:password@protocol(address)/dbname?parameters
dsn通常由以下部分组成:
- username:password - 数据库的用户名和密码
- @tcp(127.0.0.1:3306) - 数据库的IP地址和端口
- /dbname - 连接的数据库名
- charset=utf8mb4 - 字符集编码
- parseTime=True - 是否解析时间类型,如果想要正确的处理
time.Time
,则一定需要带着 - loc=Local - 时间位置信息
我们可以把连接数据库需要的所有配置信息都通过dsn字符串传递给驱动,然后驱动会根据dsn中的参数值,和数据库进行交互,建立连接。
MySQL连接示例:
go
dsn := "myuser:mypass@tcp(127.0.0.1:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local"
1.6 GORM约定
GORM 倾向于约定,而不是配置。
1.6.1 命名约定
默认情况下,GORM 使用 ID
作为主键,使用结构体名的 蛇形复数
作为表名,字段名的 蛇形
作为列名,并使用 CreatedAt
、UpdatedAt
字段追踪创建、更新时间。
这里蛇形复数
指的是:
- 蛇形(snake case),字母全部小写,单词之间用_分隔。如user_name
- 复数是在蛇形基础上,再转换为复数形式。如user_names
例如:
- 结构体名 UserInfo
- 表名会映射为 user_infos (蛇形复数)
- 字段 UserName
- 列名会映射为 user_name (蛇形形式)
- 字段 ID
- 列名会映射为 id (蛇形形式),并会作为主键
1.6.2 时间戳追踪
CreatedAt
对于有 CreatedAt
字段的模型,创建记录时,如果该字段值为零值,则将该字段的值设为当前时间
go
db.Create(&user) // 将 `CreatedAt` 设为当前时间
user2 := User{Name: "Alex", CreatedAt: time.Now()}
db.Create(&user2) // user2 的 `CreatedAt` 不会被修改
// 想要修改该值,您可以使用 `Update`
db.Model(&user).Update("CreatedAt", time.Now())
UpdatedAt
对于有 UpdatedAt
字段的模型,更新记录时,将该字段的值设为当前时间。
go
db.Save(&user) // 将 `UpdatedAt` 设为当前时间
user3 := User{Name: "Alex", UpdatedAt: time.Now()}
db.Save(&user3) // 更新时,user3 的 `UpdatedAt` 会修改为当前时间
db.Model(&user).Update("name", "Alex") // 会将 `UpdatedAt` 设为当前时间
db.Model(&user).UpdateColumn("name", "Alex") // `UpdatedAt` 不会被修改
1.7 gorm.Model
gorm.Model是一个GORM中提供的内置模型,包含一些常用字段,可以内嵌到自定义模型中使用。
gorm.Model定义如下:
go
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
它包含以下字段:
- ID:类型为uint的主键
- CreatedAt:记录首次创建时间
- UpdatedAt:记录每次更新时间
- DeletedAt:软删除时间
内嵌gorm.Model提供的好处:
- 自动获得通用字段ID,CreatedAt等,无需重复定义
- ID字段自动成为主键
- CreatedAt和UpdatedAt自动记录时间
- 获取软删除功能
使用时我们可以在模型中嵌入:
go
type User struct {
gorm.Model
Name string
}
User模型将自动获得gorm.Model的通用字段和行为,非常方便。
1.8 嵌入结构体
对于匿名字段,GORM 会将其字段包含在父结构体中,例如:
go
type User struct {
gorm.Model
Name string
}
// 等效于
type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
}
对于正常的结构体字段,你也可以通过标签 embedded
将其嵌入,例如:
go
type Author struct {
Name string
Email string
}
type Blog struct {
ID int
Author Author `gorm:"embedded"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
Name string
Email string
Upvotes int32
}
二、CRUD
2.1 创建Schema
通常在使用GORM时,通过MySQL(或其他数据库) DDL创建表结构,然后GORM将Go struct映射到表,进行CURD操作。
2.1.1 登录MySQL
建议使用数据库管理工具进行建库建表,如Navicat、DataGrip等
此处通过terminal进行演示
bash
mysql -u root -p #回车后,输入MySQL的数据库密码进行登录

2.1.2 创建数据库
bash
CREATE DATABASE `go_example_db`
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci;
说明:
- CREATE DATABASE 语句用于创建数据库
- 数据库名用反引号包裹,因为包含下划线_
- CHARACTER SET 设置字符集为utf8mb4
- COLLATE 设置排序规则为utf8mb4_general_ci
utf8mb4是MySQL支持的最大字符集,兼容所有UTF-8字符。 general_ci表示大小写不敏感的排序规则。
所以以上SQL语句创建的go_example_db数据库支持广泛的UTF-8文本,且排序和比较对大小写不敏感。

2.1.3 创建表
sql
use go_example_db; # 切换到go_example_db数据库
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) NOT NULL,
`updated_at` datetime(3) NOT NULL,
`deleted_at` datetime(3) NULL,
`name` varchar(255) NOT NULL,
`age` int unsigned NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
说明:
- 表名为结构体复数形式users
- id字段为主键自增
- 创建时间、更新时间、软删除时间映射为datetime(3) ,表示秒可以保存3位小数
- name映射为varchar类型
- 默认引擎InnoDB,字符集utf8mb4,排序规则general_ci
这个DDL创建的users表可以完整映射User结构体。

2.1.4 添加测试数据
bash
INSERT INTO `users` (`created_at`, `updated_at`, `deleted_at`, `name`,`age`)
VALUES
('2022-05-01 12:00:00.000', '2022-05-01 12:00:00.000', NULL, 'Abraham',20),
('2022-06-01 08:30:15.123', '2022-06-01 08:30:15.123', NULL, 'Benjamin',30),
('2022-07-01 23:50:55.555', '2022-07-01 23:50:55.555', NULL, 'Captain',21),
('2022-08-01 20:00:00.777', '2022-08-01 20:00:00.777', NULL, 'Dufresne',NULL),
('2022-09-01 16:20:10.520', '2022-09-01 16:20:10.520', NULL, 'Elizabeth',NULL);
添加5条测试数据用于CRUD,如有需要,可自行增加测试数据。

2.2 项目基础搭建
2.2.1 导包
需要导入gorm核心包和MySQL驱动包
go
package main
import "gorm.io/gorm"
import "gorm.io/driver/mysql"
func main() {
}
在使用包之前,如果之前没有安装过该依赖包,要记得先安装包
go
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
2.2.2 定义model
go
type User struct {
gorm.Model
Name string
}
2.2.3 连接数据库
go
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// User表结构
type User struct {
gorm.Model
Name string
Age int
}
// 获取db实例
func getMySqlDB() (*gorm.DB, error) {
dsn := "root:password@tcp(127.0.0.1:3306)/go_example_db?charset=utf8mb4&parseTime=True&loc=Local" // 连接字符串,将此处的paaword替换为MySQL的密码
db, err := gorm.Open( // 打开数据库连接
mysql.Open(dsn), // 使用MySQL驱动根据DSN的信息连接数据库
&gorm.Config{
Logger: logger.Default.LogMode(logger.Info), // 设置全局日志模式为Info,这样就可以打印sql
}) // Config{}是gorm.Config配置信息
// 返回实例db的指针和异常
return db, err
}
func main() {
db, err := getMySqlDB()
if err != nil {
panic("failed to connect database")
}
// 打印实例db
println(db)
}
2.3 Create
2.3.1 新增一条记录
go
user := User{Name: "Jessica", Age: 24} // 创建一个user实体
db.Create(&user) // 创建一条记录
println(user.ID) // 记录新增后,会返回插入数据的主键并设置到user实体上
println(result.Error) // 返回 error
println(result.RowsAffected) // 返回插入记录的条数
2.3.2 批量插入
将切片数据传递给 Create
方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
go
var users = []User{{Name: "Alex", Age: 25}, {Name: "Bob", Age: 20}, {Name: "Candy", Age: 25}}
db.Create(&users)
for _, item := range users {
println(item.ID)
}
2.3.3 选定字段创建
GORM在创建记录时,会自动处理某些特殊字段,比如:
- 有PrimaryKey标签的字段,会自动创建,即便不在Select中
- 有Default标签的字段,也会被自动处理
- 模型中的CreatedAt,UpdatedAt等通用字段会被自动创建
这是GORM的默认机制,为了自动维护某些特殊字段的值。
用选定字段的来创建
go
user := User{Name: "samuelZhang1", Age: 20}
db.Select("Name", "Age").Create(&user)
// INSERT INTO `users` (`created_at`,`updated_at`,`name`,`age`) VALUES ('2023-08-12 20:09:37.705','2023-08-12 20:09:37.705','samuelZhang1',20)
创建时排除选定字段
go
user := User{Name: "samuelZhang2", Age: 20}
db.Omit("Age").Create(&user)
// INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ('2023-08-12 20:10:50.244','2023-08-12 20:10:50.244',NULL,'samuelZhang2')
要注意,排除选定的字段需要注意可以为NULL
2.4 Read
2.4.1 主键检索
GORM 提供了 First
、Last
方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1
条件,且没有找到记录时,它会返回 ErrRecordNotFound
错误
go
// 根据主键获取第一条记录(主键升序)
user:=User{}
db.First(&user,1)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 根据主键获取最后一条记录(主键降序)
user:=User{}
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
user:=User{}
result := db.First(&user)
println(result.RowsAffected) // 返回找到的记录数
println(result.Error) // returns error
// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
2.4.2 条件检索
String 条件
go
// 获取第一条匹配的记录
db.Where("name = ?", "Alex").First(&user)
// SELECT * FROM users WHERE name = 'Alex' ORDER BY id LIMIT 1;
// IN
db.Where("name IN ?", []string{"Alex", "Samuel"}).Find(&users)
// SELECT * FROM users WHERE name IN ('Alex','Samuel');
// LIKE
db.Where("name LIKE ?", "%lex%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%lex%';
// AND
db.Where("name = ? AND age >= ?", "Alex", "22").Find(&users)
// SELECT * FROM users WHERE name = 'Alex' AND age >= 22;
// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
注意:
- 使用
First
和Last
查询单条数据时,如果查询不到,它会返回ErrRecordNotFound
错误 - 使用
Find
查询多条数据时,如果查询不到,它不会返回数据
Struct & Map 条件
go
// Struct
db.Where(&User{Name: "Alex", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "Alex" AND age = 20 ORDER BY id LIMIT 1;
// Map
db.Where(map[string]interface{}{"name": "Alex", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "Alex" AND age = 20;
// 主键切片条件
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);
注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为
0
、''
、false
,该字段不会被用于构建查询条件,例如
go
db.Where(&User{Name: "Alex", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "Alex";
您可以使用 map 来构建查询条件,例如:
go
db.Where(map[string]interface{}{"Name": "Alex", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "Alex" AND age = 0;
2.4.3 选择特定字段
选择您想从数据库中检索的字段,默认情况下会选择全部字段
go
users := make([]User, 10)
db.Select("name", "age").Where("age > ?", 10).Find(&users)
// SELECT `name`,`age` FROM `users` WHERE age > 10 AND `users`.`deleted_at` IS NULL
db.Select([]string{"name", "age"}).Find(&users)
// SELECT `name`,`age` FROM `users` WHERE age > 10 AND `users`.`deleted_at` IS NULL
2.4.4 智能选择字段
GORM 允许通过 Select
方法选择特定的字段,如果您在应用程序中经常使用此功能,你也可以定义一个较小的结构体,以实现调用 API 时自动选择特定的字段,例如:
go
type User struct {
ID uint
Name string
Age int
Gender string
// 假设后面还有几百个字段...
}
type APIUser struct {
ID uint
Name string
}
// 查询时会自动选择 `id`, `name` 字段
db.Model(&User{}).Limit(10).Find(&APIUser{})
// SELECT `id`, `name` FROM `users` LIMIT 10
2.5 Update
2.5.1 更新单个列
当使用 Update
更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause
错误,查看 Block Global Updates 获取详情。当使用了 Model
方法,且该对象主键有值,该值会被用于构建条件,例如:
go
// 条件更新
db.Model(&User{}).Where("id = ?", 1).Update("name", "hello")
// UPDATE `users` SET `name`='hello',`updated_at`='2023-08-12 19:38:13.34' WHERE id = 1 AND `users`.`deleted_at` IS NULL
user := User{}
user.ID=1
db.Model(&user).Update("name", "hello")
// UPDATE `users` SET `name`='hello',`updated_at`='2023-08-12 19:38:13.50' WHERE id = 1 AND `users`.`deleted_at` IS NULL
// 根据条件和 model 的值进行更新
user := User{}
user.ID=1
db.Model(&user).Where("age > ?",10 ).Update("name", "hello")
// UPDATE `users` SET `name`='hello',`updated_at`='2023-08-12 19:41:08.037' WHERE age > 10 AND `users`.`deleted_at` IS NULL AND `id` = 1
2.5.2 更新多列
Updates
方法支持 struct
和 map[string]interface{}
参数。当使用 struct
更新时,默认情况下,GORM 只会更新非零值的字段。
go
// 根据 `struct` 更新属性,只会更新非零值的字段
user := User{}
user.ID = 1
db.Model(&user).Updates(User{Name: "hello", Age: 0}) // Age将会被忽略
// UPDATE `users` SET `updated_at`='2023-08-12 19:45:15.084',`name`='hello' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
// 根据 `map` 更新属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 0})
user := User{}
user.ID = 1
// UPDATE `users` SET `age`=0,`name`='hello',`updated_at`='2023-08-12 20:00:13.544' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用
Select
更新选定字段,或使用map
来完成更新操作
2.5.3 更新选定字段
如果您想要在更新时选定、忽略某些字段,您可以使用 Select
、Omit
go
// Select 和 Map
user := User{}
user.ID = 1
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18}) // 将会忽略age
// UPDATE `users` SET `name`='hello',`updated_at`='2023-08-12 20:04:43.168' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
user := User{}
user.ID = 1
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 20})
// 将会忽略name
// UPDATE `users` SET `age`=20,`updated_at`='2023-08-12 20:06:01.661' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
// Select 和 Struct (可以选中更新零值字段)
db.Model(&result).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE `users` SET `updated_at`='2023-08-12 20:07:24.703',`name`='new_name',`age`=0 WHERE `users`.`deleted_at` IS NULL AND `id` = 1
2.5.4 批量更新
如果您尚未通过 Model
指定记录的主键,则 GORM 会执行批量更新
go
// 根据 struct 更新
db.Model(User{}).Where("age > ?", 30).Updates(User{Name: "hello", Age: 18})
// UPDATE `users` SET `updated_at`='2023-08-12 20:16:03.934',`name`='hello',`age`=18 WHERE age > 30 AND `users`.`deleted_at` IS NULL
// 根据 map 更新
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 0})
// UPDATE `users` SET `age`=0,`name`='hello' WHERE id IN (10,11)
db.Table直接操作数据库表:
- 不会触发模型回调函数
- 不会自动更新时间戳字段
db.Model操作模型:
- 会触发回调函数before/after update
- 会自动更新时间戳字段
所以使用db.Table进行更新时,不会触发UpdatedAt的自动更新。
2.5.5 阻止全局更新
如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause
错误
对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate
模式,例如:
go
db.Model(&User{}).Update("name", "Alex").Error // gorm.ErrMissingWhereClause
db.Model(&User{}).Where("1 = 1").Update("name", "Alex")
// UPDATE `users` SET `name`='Alex',`updated_at`='2023-08-12 20:20:54.925' WHERE 1 = 1 AND `users`.`deleted_at` IS NULL
// db.Exec("UPDATE users SET name = ?", "Alex")
// 谨慎使用,会将所有的name都设置为Alex
// UPDATE users SET name = "Alex"
dB.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "Alex")
// UPDATE `users` SET `name`='Alex',`updated_at`='2023-08-12 20:22:16.459' WHERE `users`.`deleted_at` IS NULL
2.5.6 使用 SQL 表达式更新
GORM 允许使用 SQL 表达式更新列,例如:
go
user := User{}
db.Model(&user).Where("id in ?", []uint{1, 2, 3}).Update("age", gorm.Expr("age - ?", 1))
// UPDATE `users` SET `age`=age - 1,`updated_at`='2023-08-13 14:55:07.472' WHERE id in (1,2,3) AND `users`.`deleted_at` IS NULL
user := User{}
db.Model(&user).Where("id in ?", []uint{1, 2, 3}).
Updates(map[string]interface{}{
"age": gorm.Expr("age * ? + ?", 0, 0),
"name": gorm.Expr("concat(name,?)", "db"),
})
// UPDATE `users` SET `age`=age * 0 + 0,`name`=concat(name,'db'),`updated_at`='2023-08-13 15:00:36.567' WHERE id in (1,2,3) AND `users`.`deleted_at` IS NULL
2.5.7 更新的记录数
获取受更新影响的行数
go
// 通过 `RowsAffected` 得到更新的记录数
result := db.Model(User{}).Where("age != ?", 0).Updates(User{Name: "hello", Age: 18})
// UPDATE `users` SET `updated_at`='2023-08-12 20:24:42.952',`name`='hello',`age`=18 WHERE age != 0 AND `users`.`deleted_at` IS NULL
println(result.RowsAffected) // 更新的记录数
println(result.Error) // 更新的错误
2.6 Delete
2.6.1 物理删除
删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete,例如:
go
// User表结构
type User struct {
Name string
Age int
}
// 根据整形主键的删除
db.Delete(&User{}, 10)
// DELETE from `users` where `users`.`id` = 10;
// 根据额外条件的删除 (下面的例子将会批量删除)
db.Where("name = ?", "Alex").Delete(&User{},[]int{1,2,3})
// DELETE from `users`WHERE name = 'Alex' AND `users`.`id` IN (1,2,3);
2.6.2 软删除
如果您的模型包含了一个 gorm.deletedat
字段(gorm.Model
已经包含了该字段),它将自动获得软删除的能力!
拥有软删除能力的模型调用 Delete
时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt
置为当前时间, 并且你不能再通过正常的查询方法找到该记录。
go
// User表结构
type User struct {
gorm.Model
Name string
Age int
}
// 根据整形主键的删除
db.Delete(&User{}, 10)
// UPDATE `users` SET `deleted_at`='2023-08-13 15:04:13.696' WHERE `users`.`id` = 10 AND `users`.`deleted_at` IS NULL
// 根据额外条件的删除 (下面的例子将会批量删除)
db.Where("name = ?", "Alex").Delete(&User{},[]int{1,2,3})
// UPDATE `users` SET `deleted_at`='2023-08-13 15:07:52.874' WHERE name = 'Alex' AND `users`.`id` IN (1,2,3) AND `users`.`deleted_at` IS NULL
查找被软删除的记录
您可以使用 Unscoped
找到被软删除的记录
go
users := make([]User, 10)
db.Unscoped().Where("name = ?", "Alex").Find(&users)
// SELECT * FROM `users` WHERE name = 'Alex'
永久删除
您也可以使用 Unscoped
永久删除匹配的记录
go
db.Unscoped().Where("name = ?", "Alex").Delete(&User{})
// DELETE FROM `users` WHERE name = 'Alex'
三、 总结
- 导入GORM核心包,以及具体数据库的驱动包
- 使用
db.Select
和db.Omit
来选择和排除字段,要注意字段是否允许为NULL
- 查询或更新零值(
0
、''
、false
),请使用Where|Update(map[string]interface{}{"age":0})
或Where|Update("age = 0")
构建查询条件 - 创建使用
db.Create
- 多条数据使用切片
- 返回新增主键、影响行数和异常
- 查找使用
db.Find
- 通过
Where
、Or
条件语句构建查询条件 - 单条语句手动使用
limit
进行限制 - 返回查找行数和异常
- 通过
- 更新使用
db.Update
- 单列使用
db.Model(User{}).Update
- 多累使用
db.Model(User{}).Updates
- 也可以使用SQL表达式作为更新的值
db.Model(User{}).Update("age", gorm.Expr("age - ?", 1))
- 返回更新行数和异常
- 单列使用
- 删除使用
db.Delete
- 如果Model中不包含
gorm.deletedat
字段,则会进行物理删除 - 如果Model中包含
gorm.deletedat
字段,则会进行逻辑删除,即软删除- 使用
db.Unscoped()
,查找被标记为软删除的记录 - 使用
db.Unscoped().Delete
,对软删除的记录进行物理删除 - 返回删除行数和异常
- 使用
- 如果Model中不包含