XORM 项目实践总结
安装⌗
go get xorm.io/xorm
# 安装对应的数据库驱动
go get github.com/go-sql-driver/mysql
奇技淫巧⌗
官方文档里有的我这里就不再赘述了,下面将介绍一些有用但官方文档里没有的内容。
继承⌗
当我们的业务中多个模型中的部分字段是相同的,一般做法是在每个模型中重复定义,这样做不仅费时费力,而且容易出错。那么 XORM 可以在 Tag 中指定 extends
来实现对 Struct 的继承,举个例子:
如业务中我们需要去存储 Google、Baidu 的统计数据,很多字段是可以公用的,那么我们可以定义一个单独的 Struct 来存放这些公共的字段。然后在需要的 Struct 中进行继承即可。
type Report struct {
Date string `json:"date" xorm:"DATE NOT NULL COMMENT('日期')"`
Impression float64 `json:"impression" xorm:"INT(11) NOT NULL DEFAULT 0 COMMENT('展现')"`
Click float64 `json:"click" xorm:"INT(11) NOT NULL DEFAULT 0 COMMENT('点击')"`
Cost float64 `json:"cost" xorm:"FLOAT NOT NULL DEFAULT 0 COMMENT('消费')"`
Ctr float64 `json:"ctr" xorm:"FLOAT NOT NULL DEFAULT 0 COMMENT('点击率')"`
Cpm float64 `json:"cpm" xorm:"FLOAT NOT NULL DEFAULT 0 COMMENT('均价')"`
Pv float64 `json:"pv" xorm:"INT(11) NOT NULL DEFAULT 0 COMMENT('页面浏览量')"`
Uv float64 `json:"uv" xorm:"INT(11) NOT NULL DEFAULT 0 COMMENT('访客数量')"`
}
type ReportBaidu struct {
Id int64 `json:"id" xorm:"BIGINT(20) PK AUTOINCR COMMENT('ID')"`
Report `xorm:"extends"`
Ar float64 `json:"ar" xorm:"FLOAT NOT NULL DEFAULT 0 COMMENT('抵达率')"`
CreatedAt Time `json:"created_at" xorm:"DATETIME NOT NULL CREATED COMMENT('创建时间')"`
}
type ReportGoogle struct {
Id int64 `json:"id" xorm:"BIGINT(20) PK AUTOINCR COMMENT('ID')"`
Report `xorm:"extends"`
CreatedAt Time `json:"created_at" xorm:"DATETIME NOT NULL CREATED COMMENT('创建时间')"`
}
忽略字段⌗
使用 Omit()
来指定要忽略的字段,查询和更新都可以使用。
_, err := Engine.Where(builder.Eq{"id": report.Id}).Omit("updated_at").Update(report)
Migration⌗
用过 Laravel 的都知道 Laravel 使用 migration 来管理项目的数据表,那么在 XORM 中也有实现,只不过并非是开箱即用的。执行 migrate 的逻辑需要自己实现。如下代码所示,我们采用 XORM 提供的 Sync2 方法进行 migrate:
package models
import (
"xorm.io/xorm"
"xorm.io/xorm/migrate"
)
var tables = []interface{}{
&Job{},
//&RawData{},
ReportTotal{},
&ReportBaidu{},
&ReportUmeng{},
&ReportApplet{},
&ReportGoogle{},
}
var migrations = []*migrate.Migration{
{
ID: "2020071502",
Migrate: func(engine *xorm.Engine) error {
return engine.Charset("utf8mb4").Sync2(tables...)
},
Rollback: func(engine *xorm.Engine) error {
return engine.DropTables(tables...)
},
},
}
func Migrate() error {
m := migrate.New(Engine, &migrate.Options{
TableName: "migrations",
IDColumnName: "id",
}, migrations)
return m.Migrate()
}
只需要在业务逻辑中调用 Migrate 函数即可实现迁移。
Seed⌗
这部分内容可以参考我之前的文章Go 实现 Database Seeder
遇到的坑⌗
Update⌗
在实际的项目中,我发现当我们进行 Update 某条数据时,如果某个字段为零值则这个字段会被忽略,比如当前 Uv 字段值为 10,Update 时的 Uv 值设为 0 时,更新后的结果是 Uv 依然为 10。
为了避免这种问题我们需要指定更新字段,可以使用 Cols
来指定部分字段,也可以直接使用 AllCols
设置更新全部字段:
_, err := Engine.Where(builder.Eq{"id": report.Id}).Cols("uv","pv").Update(report)
_, err := Engine.Where(builder.Eq{"id": report.Id}).AllCols().Update(report)
Migrations⌗
Migrations 表的 ID 字段使用的是 VARCHAR(255)
,如果在 MySQL 5.7 以前的版本,执行迁移时会报错,原因是主键的长度超出了最大限制。遇到这种情况,要么使用 5.7 及以后的版本,要么修改默认配置。
I hope this is helpful, Happy hacking…