Gorm/GEN入门,支持mysql 的Json字段

1,378 阅读2分钟

背景

在使用MySQL的时候经常会想存储一些简单的结构化数据,例如JSON结构体,但是用MySQL的原生字段类型存储就比较困难,需要对应到表上。对于这种情况,可以考虑使用非关系型数据库(Nonrelational database),例如MongoDB来存储数据。但是对于已经使用了MySQL数据库的项目,再增加数据库也不可避免地增加了项目复杂度,此时还有另一种选择,那就是MySQL的JSON字段。

本文会从创建数据库表开始,用GEN对数据库表生成MySQL的GORM代码,再使用GORM操作数据库的JSON字段,所以也可以参考此文档了解GORM和GEN的使用。

准备知识

本文会使用到Hertz框架、GORM、GEN数据库脚手架。

  1. 可以用Hertz创建Go的HTTP项目,里面带有GEN的相关代码和MySQL客户端初始化代码。
  2. MySQL在版本5.*之后开始支持JSON类型,关于MySQL的JSON类型的文档可参考官方文档 ↗
  3. GORM不原生支持JSON类型的操作,需要扩展自定义类型支持,自定义数据类型的文档可参考GORM的官方文档 ↗
  4. 可以直接使用开源库中的JSON类型扩展,例如GORM的datatypes包 ↗
  5. 使用GEN根据数据库表生成数据库操作代码。

使用

数据库表结构

User表

create table User (
    id            bigint auto_increment comment 'id'         primary key,
    created_at    timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'created_at',
    updated_at    timestamp                            null comment 'updated_at',
    test_map      text                                 null comment 'test_map'
)   comment 'user';

对应的数据库表结构

GEN生成GORM代码

GEN脚本generate.sh,可以使用Hertz Tool生成目录结构的时候带上。

GEN代码cmd/generate/generate.go

g.ApplyBasic(
    g.GenerateModel("user",
        gen.FieldGORMTag("test_map", func(tag field.GormTag) field.GormTag {
            return field.GormTag{"gorm": []string{"type:json"}}
        }),
        gen.FieldType("test_map", "datatypes.JSON"),
    ),
)

生成的数据库表结构

const TableUser = "user"

type User struct {
    ID        int64             `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true;comment:id" json:"id"` // id
    TestMap   datatypes.JSON    `gorm:"gorm:type:json" json:"test_map"`
}

// TableName User's table name
func (*User) TableName() string {
    return "TableNameUser"
}

JSON字段的数据库操作(Go伪代码)

type TestMap map[string]string

ctx := context.Background()
db := mysql.WDB(ctx)
p := query.Use(db).User

err := p.WithContext(ctx).Create(&model.User{
    TestMap: datatypes.JSON([]byte(`{"created":"successful"}`)),
})
if err != nil {
    fmt.Printf("err:%+v\n", err)
    return
}

result, err := p.WithContext(ctx).Where(p.ID.Eq(1)).Update(p.TestMap, datatypes.JSON(`{"created":"successful"}`))
if err != nil {
    fmt.Printf("err:%+v\n", err)
    return
}

first, err := p.WithContext(ctx).Where(p.ID.Eq(1)).First()
fmt.Printf("query first:%+v, err:%s", first, err)

testMapJSON := first.TestMap
mMap := new(TestMap)
json.Unmarshal(testMapJSON, &mMap)
fmt.Printf("Unmarshal mMap:%+v", mMap)