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 数据库中的 postscomments 表,然后运行这段代码看看结果是否符合预期:

-w1007

可以看到,数据表的插入和关联查询结果都是正常的。下面我们简单分析下这段示例代码。

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
}

这里定义了两个模型类,PostComment,分别对应数据表 postscomments,并且在 Post 中通过如下方式定义了 PostComment 之间的一对多关联:

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)

模型类中的 IdCreatedAt 字段系统会自动维护,不需要显示设置。

注:如果要实现修改、删除和查询操作,请参考 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 语言本身的优势所在。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 数据表之间关联关系和关联查询

>> 下一篇: 常见的并发模式实现(一):调度后台处理任务的作业程序