GORM 使用入门
ORM 与 GORM
我们已经成功存储数据到数据表,但是所有操作都要自行编写代码,很多编程语言和框架会引入 ORM 来解决模型类与数据表记录的映射关系,ORM 架起了 SQL 语句和应用程序之间的桥梁,将模型类和数据表映射起来,将模型类字段和数据表字段建立关联。
典型的 ORM 库比如 Java 中的 Hibernate、Ruby 中的 ActiveRecord、以及 Laravel 中的 Eloquent。
在 Go 语言中,也有这样的 ORM 库,最流行的当属 GORM。
GORM 是一个适用于 Go 语言的 ORM 库,遵循 ActiveRecord 模式进行设计。
注:ORM 有两种实现方式 —— ActiveRecord 和 DataMapper,关于两者之间的区别可以参考这篇教程。
GORM 的功能非常强大,除了基本的基于模型类对数据表进行增删改查之外,还支持定义关联关系、执行数据表迁移、查询链以及很多其他高级特性,并且支持在特定事件发生时(比如插入、更新、删除)触发指定的回调函数(类似 Laravel 框架的模型事件)。
下面我们来简单演示下如何基于 GORM 进行增删改查和关联查询。
GORM 使用示例
使用之前需要先安装 GORM:
go get github.com/jinzhu/gorm
然后我们编写一段示例代码:
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
type Post struct {
Id int
Title string
Content string
Author string `sql:"not null"`
CreatedAt time.Time
Comments []Comment
}
type Comment struct {
Id int
Content string
Author string `sql:"not null"`
PostId int `sql:"index"`
CreatedAt time.Time
}
var DbConn *gorm.DB
func init() {
var err error
DbConn, err = gorm.Open("mysql", "root:root@/test_db?charset=utf8mb4&parseTime=true")
if err != nil {
panic(err)
}
DbConn.AutoMigrate(&Post{}, &Comment{})
}
func main() {
post := Post{Title: "GORM 示例教程", Content: "基于 GORM 进行数据库增删改查", Author: "学院君"}
// 通过 GORM 插入文章记录
DbConn.Create(&post)
fmt.Println(post)
// 通过关联关系新增评论并将其附加到对应的文章记录
comment := Comment{Content: "Test Comment", Author: "学院君小号"}
DbConn.Model(&post).Association("Comments").Append(comment)
// 查询文章记录
var gormPost Post
DbConn.Where("author = ?", "学院君").First(&gormPost)
// 查询包含评论数据的文章记录
var comments []Comment
DbConn.Model(&gormPost).Related(&comments)
fmt.Println(comments[0])
}
由于 GORM 会根据模型类结构体声明自动创建对应的数据表,所以我们可以删除 test_db
数据库中的 posts
和 comments
表,然后运行这段代码看看结果是否符合预期:
可以看到,数据表的插入和关联查询结果都是正常的。下面我们简单分析下这段示例代码。
GORM 运行原理
数据库连接
由于 GORM 也实现了 database/sql
接口,所以建立数据库连接和之前使用 go-sql-driver/mysql
包类似,只是调用方法改成了 gorm.Open
:
DbConn, err = gorm.Open("mysql", "root:root@/test_db?charset=utf8mb4&parseTime=true")
参数和之前完全一样,引入的驱动包调整为 jinzhu/gorm
即可:
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
注:更多关于 GORM 数据库连接配置的细节,请参考 GORM 官方文档。
数据表自动迁移
和使用 go-sql-driver/mysql
包不同的是,这次我们不再需要手动创建数据表,因为 GORM 提供了数据表自动迁移功能:
DbConn.AutoMigrate(&Post{}, &Comment{})
通过 AutoMigrate
方法传入要迁移的模型类实例即可,GORM 会自动创建对应的数据表,表名规则是模型类名小写的复数形式。
模型类定义
接下来,我们看下模型类的定义:
type Post struct {
Id int
Title string
Content string
Author string `sql:"not null"`
CreatedAt time.Time
Comments []Comment
}
type Comment struct {
Id int
Content string
Author string `sql:"not null"`
PostId int `sql:"index"`
CreatedAt time.Time
}
这里定义了两个模型类,Post
和 Comment
,分别对应数据表 posts
和 comments
,并且在 Post
中通过如下方式定义了 Post
和 Comment
之间的一对多关联:
Comments []Comment
这里我们没有用结构体标签指定关联外键(GORM 支持通过结构体标签设置数据表字段属性),GORM 底层会自动维护这个关联,默认规则是在 Comment
中的 PostId
字段(即当前模型类名加上主键 ID 后缀)。
但是还是有一些字段设置了结构体标签,这是为了给该字段添加额外的数据表字段约束,比如索引、是否允许为空等:
Author string `sql:"not null"`
PostId int `sql:"index"`
注:更多模型类定义的细节和结构体标签设置,请参考 GORM 官方文档。
增删改查
我们继续来看增删改查和关联模型的操作,在 GORM 中,我们总算不用维护 SQL 语句了,所有的增删改查操作都可以通过 GORM 库提供的方法来实现,比如要创建一条记录可以这么做:
post := Post{Title: "GORM 示例教程", Content: "基于 GORM 进行数据库增删改查", Author: "学院君"}
DbConn.Create(&post)
模型类中的 Id
和 CreatedAt
字段系统会自动维护,不需要显示设置。
注:如果要实现修改、删除和查询操作,请参考 GORM 官方文档 CRUD 接口部分,这些也都有相应的内置方法。
关联查询
如果要在上述模型实例上创建与之关联的评论,可以这么做:
comment := Comment{Content: "Test Comment", Author: "学院君小号"}
DbConn.Model(&post).Association("Comments").Append(comment)
最后要查询包含关联评论记录的主题,可以这么做:
var gormPost Post
DbConn.Where("author = ?", "学院君").First(&gormPost)
var comments []Comment
DbConn.Model(&gormPost).Related(&comments)
注:更多关联查询和操作的使用,请参考 GORM 官方文档的关联部分。
小结
可以看到,引入 GROM 之后,我们不再需要手动编写复杂的 SQL 语句,只需要借助 GORM 提供的方法就可以非常便捷地完成数据库交互,这极大简化了我们日常开发的代码编写和维护成本,也降低了安全风险,所有的 SQL 语句都由 GORM 底层去构建并执行,它会将上层模型实例的增删改查、关联操作方法执行转化为相应的 SQL 语句去执行,这也是 ORM 的设计初衷。
以上只是 GORM 的简单示例,完整功能请阅读官方文档,需要指出的是 GORM 的作者是中国人,所以中文文档支持非常友好。
关于 Go 语言的数据库操作部分,我们就简单介绍到这里,到目前为止,还并没有看到 Go 语言相对于 PHP 开发 Web 应用的任何优势,接下来,我们来看看 Go 语言 Web 编程的重头戏 —— 并发编程,这也是 Go 语言本身的优势所在。
3 Comments
go get github.com/jinzhu/gorm 为什么是
jinzhu
get 后面就是一个完整的 Github 项目地址
GORM V2版使用:go get gorm.io/gorm