Go 数据存储篇(七):GORM 使用入门

2020-10-19 09:47:09 浏览数 (1)

1、ORM 与 GORM

我们已经成功存储数据到数据表,但是所有操作都要自行编写代码,很多编程语言和框架会引入 ORM 来解决模型类与数据表记录的映射关系,ORM 架起了 SQL 语句和应用程序之间的桥梁,将模型类和数据表映射起来,将模型类字段和数据表字段建立关联。

典型的 ORM 库比如 Java 中的 Hibernate、Ruby 中的 ActiveRecord、以及 Laravel 中的 Eloquent。

在 Go 语言中,也有这样的 ORM 库,最流行的当属 GORM。

GORM 是一个适用于 Go 语言的 ORM 库,遵循 ActiveRecord 模式进行设计。

注:ORM 有两种实现方式 —— ActiveRecord 和 DataMapper,关于两者之间的区别可以参考这篇教程:https://xueyuanjun.com/post/966.html。

GORM 的功能非常强大,除了基本的基于模型类对数据表进行增删改查之外,还支持定义关联关系、执行数据表迁移、查询链以及很多其他高级特性,并且支持在特定事件发生时(比如插入、更新、删除)触发指定的回调函数(类似 Laravel 框架的模型事件)。

下面我们来简单演示下如何基于 GORM 进行增删改查和关联查询。

2、GORM 使用示例

使用之前需要先安装 GORM:

代码语言:javascript复制
go get github.com/jinzhu/gorm

然后我们编写一段示例代码:

代码语言:javascript复制
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 表,然后运行这段代码看看结果是否符合预期:

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

3、GORM 运行原理

数据库连接

由于 GORM 也实现了 database/sql 接口,所以建立数据库连接和之前使用 go-sql-driver/mysql 包类似,只是调用方法改成了 gorm.Open

代码语言:javascript复制
DbConn, err = gorm.Open("mysql", "root:root@/test_db?charset=utf8mb4&parseTime=true")

参数和之前完全一样,引入的驱动包调整为 jinzhu/gorm 即可:

代码语言:javascript复制
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"

注:更多关于 GORM 数据库连接配置的细节,请参考 GORM 官方文档(https://gorm.io/zh_CN/docs/)。

数据表自动迁移

和使用 go-sql-driver/mysql 包不同的是,这次我们不再需要手动创建数据表,因为 GORM 提供了数据表自动迁移功能:

代码语言:javascript复制
DbConn.AutoMigrate(&Post{}, &Comment{})

通过 AutoMigrate 方法传入要迁移的模型类实例即可,GORM 会自动创建对应的数据表,表名规则是模型类名小写的复数形式。

模型类定义

接下来,我们看下模型类的定义:

代码语言:javascript复制
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 之间的一对多关联:

代码语言:javascript复制
Comments []Comment

这里我们没有用结构体标签指定关联外键(GORM 支持通过结构体标签设置数据表字段属性),GORM 底层会自动维护这个关联,默认规则是在 Comment 中的 PostId 字段(即当前模型类名加上主键 ID 后缀)。

但是还是有一些字段设置了结构体标签,这是为了给该字段添加额外的数据表字段约束,比如索引、是否允许为空等:

代码语言:javascript复制
Author string `sql:"not null"`
PostId int `sql:"index"`

注:更多模型类定义的细节和结构体标签设置,请参考 GORM 官方文档。

增删改查

我们继续来看增删改查和关联模型的操作,在 GORM 中,我们总算不用维护 SQL 语句了,所有的增删改查操作都可以通过 GORM 库提供的方法来实现,比如要创建一条记录可以这么做:

代码语言:javascript复制
post := Post{Title: "GORM 示例教程", Content: "基于 GORM 进行数据库增删改查", Author: "学院君"}
DbConn.Create(&post)

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

注:如果要实现修改、删除和查询操作,请参考 GORM 官方文档 CRUD 接口部分,这些也都有相应的内置方法。

关联查询

如果要在上述模型实例上创建与之关联的评论,可以这么做:

代码语言:javascript复制
comment := Comment{Content: "Test Comment", Author: "学院君小号"}
DbConn.Model(&post).Association("Comments").Append(comment)

最后要查询包含关联评论记录的主题,可以这么做:

代码语言:javascript复制
var gormPost Post
DbConn.Where("author = ?", "学院君").First(&gormPost)

var comments []Comment
DbConn.Model(&gormPost).Related(&comments)

注:更多关联查询和操作的使用,请参考 GORM 官方文档的关联部分。

4、小结

可以看到,引入 GROM 之后,我们不再需要手动编写复杂的 SQL 语句,只需要借助 GORM 提供的方法就可以非常便捷地完成数据库交互,这极大简化了我们日常开发的代码编写和维护成本,也降低了安全风险,所有的 SQL 语句都由 GORM 底层去构建并执行,它会将上层模型实例的增删改查、关联操作方法执行转化为相应的 SQL 语句去执行,这也是 ORM 的设计初衷。

以上只是 GORM 的简单示例,完整功能请阅读官方文档(https://gorm.io/zh_CN/docs/),需要指出的是 GORM 的作者是中国人,所以中文文档支持非常友好。

关于 Go 语言的数据库操作部分,我们就简单介绍到这里,到目前为止,还并没有看到 Go 语言相对于 PHP 开发 Web 应用的任何优势,接下来,我们来看看 Go 语言 Web 编程的重头戏 —— 并发编程,这也是 Go 语言本身的优势所在。

(全文完)

0 人点赞