从 go-pg 迁移
Bun 是 go-pg 的重写版本,它支持 PostgreSQL、MySQL 和 SQLite。它包含
- Bun 核心,提供查询构建器和模型。
- pgdriver 包,用于连接到 PostgreSQL。
- migrate 包,用于运行迁移。
- dbfixture,用于从 YAML 文件加载初始数据。
- 可选的 入门套件,提供现代应用程序骨架。
Bun 的查询构建器试图与 go-pg 的构建器兼容,但一些很少使用的 API 已被删除(例如,WhereOrNotGroup
)。在大多数情况下,您无需重写查询。
go-pg 仍在维护,将 go-pg 应用程序重写为 Bun 没有紧迫性,但新项目应该优先选择 Bun 而不是 go-pg。一旦您熟悉了更新的 API,您应该能够在一天内将一个 80-100k 行的 go-pg 应用程序迁移到 Bun。
新功能
*pg.Query
被拆分为更小的结构,例如,bun.SelectQuery,bun.InsertQuery,bun.UpdateQuery,bun.DeleteQuery 等等。这是 Bun 插入/更新数据比 go-pg 更快的其中一个原因。go-pg API
err := db.ModelContext(ctx, &users).Select() err := db.ModelContext(ctx, &users).Select(&var1, &var2) res, err := db.ModelContext(ctx, &users).Insert() res, err := db.ModelContext(ctx, &user).WherePK().Update() res, err := db.ModelContext(ctx, &users).WherePK().Delete()
Bun API
err := db.NewSelect().Model(&users).Scan(ctx) err := db.NewSelect().Model(&users).Scan(ctx, &var1, &var2) res, err := db.NewInsert().Model(&users).Exec(ctx) res, err := db.NewUpdate().Model(&users).WherePK().Exec(ctx) res, err := db.NewDelete().Model(&users).WherePK().Exec(ctx)
要创建
VALUES (1, 'one')
语句,请使用db.NewValues(&rows)
。批量
UPDATE
查询应该使用 CTE 和VALUES
语句重写db.NewUpdate(). With("_data", db.NewValues(&rows)). Model((*Model)(nil)). Table("_data"). Set("model.name = _data.name"). Where("model.id = _data.id"). Exec(ctx)
或者,您可以使用
UpdateQuery.Bulk
助手,它执行相同的操作err := db.NewUpdate().Model(&rows).Bulk().Exec(ctx)
要创建索引,请使用
db.NewCreateIndex()
。要删除索引,请使用
db.NewDropIndex()
。要截断表,请使用
db.NewTruncateTable()
。要覆盖模型表名,请使用
q.Model((*MyModel)(nil)).ModelTableExpr("my_table_name")
。要提供初始数据,请使用 夹具.
Go 零值和 NULL
与 go-pg 不同,Bun 默认情况下不会将 Go 零值序列化为 SQL NULL。要获得旧的行为,请使用 nullzero
标签选项
type User struct {
Name string `bun:",nullzero"`
}
对于 time.Time
字段,您可以使用 bun.NullTime
type User struct {
Name string `bun:",nullzero"`
CreatedAt time.Time `bun:",notnull,default:current_timestamp"`
UpdatedAt bun.NullTime
}
其他更改
- 将
pg
结构标签替换为bun
,例如,bun:"my_column_name"
。 - 将
rel:"has-one"
替换为rel:"belongs-to"
,将rel:"belongs-to"
替换为rel:"has-one"
。go-pg 对这些关系使用了错误的名称。 - 将
tableName struct{} `pg:"mytable`"
替换为bun.BaseModel `bun:"mytable"`
。这有助于 linter 标记该字段为未使用。 - 要将 Go 零值序列化为 NULL,请使用
bun:",nullzero"
字段标签。默认情况下,Bun 不再将 Go 零值序列化为NULL
。 - 将
pg.ErrNoRows
替换为sql.ErrNoRows
。 - 将
db.WithParam
替换为db.WithNamedArg
。 - 将
orm.RegisterTable
替换为db.RegisterModel
。 - 将
pg.Safe
替换为bun.Safe
。 - 将
pg.Ident
替换为bun.Ident
。 - 将
pg.Array
替换为pgdialect.Array
。 - 将
pg:",discard_unknown_columns"
替换为db.WithDiscardUnknownColumns()
选项。 - 将
q.OnConflict("DO NOTHING")
替换为q.On("CONFLICT DO NOTHING")
。 - 将
q.OnConflict("(column) DO UPDATE")
替换为q.On("CONFLICT (column) DO UPDATE")
。 - 将
ForEach
替换为sql.Rows
和db.ScanRow
。 - 将
WhereIn("foo IN (?)", slice)
替换为Where("foo IN (?)", bun.In(slice))
。 - 将
db.RunInTransaction
替换为db.RunInTx
。 - 将
db.SelectOrInsert
替换为 upsert
res, err := db.NewInsert().Model(&model).On("CONFLICT DO NOTHING").Exec(ctx)
res, err := db.NewInsert().Model(&model).On("CONFLICT DO UPDATE").Exec(ctx)
- 将
q.UpdateNotZero()
替换为更新查询上的q.OmitZero()
// go-pg API:
res, err := db.Model(&model).WherePK().UpdateNotZero()
// bun API:
res, err := db.NewUpdate().Model(&model).WherePK().OmitZero().Exec(ctx)
- Bun 使用 database/sql 池,因此请使用 sql.DBStats 而不是
pg.PoolStats.
WrapWith
已被删除。请改用With
subq := db.NewSelect()
q := db.NewSelect().
With("subq", subq).
Table("subq")
忽略的列
与 go-pg 不同,Bun 不允许扫描到明确忽略的字段。例如,以下代码不起作用
type Model struct {
Foo string `bun:"-"`
}
但是您可以通过添加 scanonly
选项来修复它
type Model struct {
Foo string `bun:",scanonly"`
}
pg.Listener
如果您需要 pg.Listener
,您有 2 个选项
- 使用 pgdriver.Listener.
- 使用 pgx.
移植迁移
Bun 通过 bun/migrate 包支持迁移。因为它使用基于时间戳的迁移名称,您需要重命名迁移文件,例如,1_initial.up.sql
应该重命名为 20210505110026_initial.up.sql
。
完成迁移移植后,您需要初始化 Bun 表(使用 入门套件)
go run cmd/bun/main.go -env=dev db init
并且可能将现有迁移标记为已完成
go run cmd/bun/main.go -env=dev db mark_applied
您可以使用以下命令检查迁移的状态
go run cmd/bun/main.go -env=dev db status
监控性能
要 监控 Bun 性能,您可以使用 Bun 附带的 OpenTelemetry 监控。
OpenTelemetry 是一个开源项目,旨在提供一组统一的 API、库、代理和监控,以在现代软件应用程序中实现可观察性。它允许开发人员从其应用程序中收集、监控和导出遥测数据,以深入了解分布式系统的性能和行为。
Uptrace 是一个 OpenTelemetry APM,支持分布式跟踪、指标和日志。您可以使用它来监控应用程序并排查问题。
Uptrace 带有一个直观的查询构建器、丰富的仪表板、带有通知的警报规则以及大多数语言和框架的集成。
Uptrace 可以在一台服务器上处理数十亿个跨度和指标,并允许您以 10 倍更低的成本监控您的应用程序。
只需几分钟,您就可以通过访问 云演示 (无需登录)或使用 Docker 在本地运行它。源代码可在 GitHub 上获取。