背景
在使用MySQL的时候经常会想存储一些简单的结构化数据,例如JSON结构体,但是用MySQL的原生字段类型存储就比较困难,需要对应到表上。对于这种情况,可以考虑使用非关系型数据库(Nonrelational database),例如MongoDB来存储数据。但是对于已经使用了MySQL数据库的项目,再增加数据库也不可避免地增加了项目复杂度,此时还有另一种选择,那就是MySQL的JSON字段。
本文会从创建数据库表开始,用GEN对数据库表生成MySQL的GORM代码,再使用GORM操作数据库的JSON字段,所以也可以参考此文档了解GORM和GEN的使用。
准备知识
本文会使用到Hertz框架、GORM、GEN数据库脚手架。
- 可以用Hertz创建Go的HTTP项目,里面带有GEN的相关代码和MySQL客户端初始化代码。
- MySQL在版本5.*之后开始支持JSON类型,关于MySQL的JSON类型的文档可参考官方文档 ↗。
- GORM不原生支持JSON类型的操作,需要扩展自定义类型支持,自定义数据类型的文档可参考GORM的官方文档 ↗。
- 可以直接使用开源库中的JSON类型扩展,例如GORM的datatypes包 ↗。
- 使用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)