1. 前言
这篇文章中,我们将会来学习如何实际地使用 GORM 连接数据库,并进行各种各样的 CRUD 操作。
2. 环境准备
在使用 GORM 之前,我们需要先在自己的项目中引入 GORM 以及所需要用到的数据库驱动,这里以 SQLite 举例。首先创建一个空白的 Go 项目,然后在代码文件中输入如下内容:
package main
import (
"fmt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
fmt.Println("Open failed:", err)
return
}
_ = db
}
这时候直接执行 go run . 肯定是不行的,编译器会提示找不到所需的 GORM 包,并且给出建议。但 Go 给出的建议其实并不够方便,我们只需要执行 go mod tidy 即可,它会保证 go.mod 与源代码内容相匹配,并且能够自动下载缺失的包,十分方便。执行效果如图:
接下来再执行 go run .,程序就能正常编译运行了。执行完毕后,应当能看到项目目录下出现了 test.db。
3. 增删改查
接下来需要定义模型(Model),这是 GORM 等 ORM 库中的操作的基本单元。在 GORM 中,模型可以简单地看作是一个普通的结构体。以下代码就定义了一个最简单的模型类型:
type User struct {
Name string
}
此时你已经可以开始使用这个模型来进行 CRUD 了,简单的操作方式如下:
func run(db *gorm.DB) {
var user User
// 增
db.Create(&User{Name: "user1"})
db.Create(&User{Name: "user2"})
// 删
db.Delete(&User{}, "name = ?", "user2")
// 改
db.Model(&User{}).Where("name = ?", "user1").Update("name", "user3")
// 查
db.First(&user)
fmt.Println(user)
}
注意部分 API 中需要用 Model()、Where() 等方式来指定操作范围,然后才能继续操作,否则 GORM 可能会找不到操作目标,或者是以危险操作为由拒绝执行。如果你直接尝试执行这段代码的话,其实并不会有任何效果,并且 GORM 会报错:
原因也很简单:我们刚刚才新建了一个数据库,其内部是空的,没有任何表,自然没办法操作数据。幸好 GORM 提供了一个方便的功能,使得我们可以一键建表,或者更新表中的字段等信息:
db.AutoMigrate(&User{})
在 CRUD 的代码前面加上这行代码,再重新运行代码,问题就迎刃而解了,在数据库中也能看到数据的变化:
值得注意的是,上面定义的 User 模型实在是太简单了,以至于它完全不适合实际于实际的业务操作。这里给出一个更复杂、更切合实际场景的模型定义:
type User struct {
ID uint
Name string `gorm:"unique"`
Email *string
Age uint8
CreatedAt time.Time
UpdatedAt time.Time
}
这个结构体中字段的命名和 tag 等并非空穴来风,而是涉及到了一些 GORM 的约定与惯例:
ID会被 GORM 设置为主键(即PK);CreatedAt与UpdatedAt会被 GORM 用于记录当前 record 的创建时间与更新时间;- 模型对应的表名是自动从类型名生成的,如
User会变为users,字段名也类似; `gorm:"unique"`是 Go 结构体的一个语法元素,被称作 struct tag,可以通过反射机制获取其内容,GORM 便利用了这个功能对字段进行特殊标记,如unique就表示字段是唯一的,不可重复出现。
当然,GORM 定义模型的花样不止如此,比如下面这段代码:
type User struct {
gorm.Model
Name string
}
便巧妙地利用了 Go 语言与 GORM 的各种特性,如匿名字段内部的字段定义会被自动展开到上一层,而 gorm.Model 内部的 DeletedAt 则使得模型自动拥有了软删除能力,等等。最终的结构体在效果上等价于
type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
}
可见 GORM 的操作十分简单优雅。
4. 总结
在这次 GORM 的探索与实践中,我学习到了一些基本的基于 GORM 对数据库的操作,当然这些知识也只是 GORM 的冰山一角,其还有许多特性可以去探索,如错误处理、原生 SQL 执行、模型关联与 FK、钩子等,以后有机会的话会更深入地进行学习。