GoFr 如何用 gofr migrate create 生成带时间戳的数据库迁移模板与自动注册表
2026/9/14 5:41:52 网站建设 项目流程

GoFr 如何用 gofr migrate create 生成带时间戳的数据库迁移模板与自动注册表

【免费下载链接】gofrAn opinionated GoLang framework for accelerated microservice development. Built in support for databases and observability.项目地址: https://gitcode.com/GitHub_Trending/go/gofr

在一个多人协作的 GoFr 服务里,数据库结构变更需要可追踪、可重放:每个迁移要有明确的版本,且同一批迁移不能在不同环境里重复执行。GoFr CLI 的gofr migrate create命令可以一步完成两件重复工作——在migrations目录生成带时间戳前缀的迁移模板文件,并自动维护一个登记所有迁移的all.go注册表。本文按「安装 CLI → 生成迁移 → 填充模板 → 接入 main.go → 运行验证」的路径走一遍完整流程。

准备条件

根据 GoFr CLI 参考文档,使用 GoFr CLI 需要:

  • Go 1.25 或更高版本,可用以下命令检查:
go version
  • 安装 GoFr CLI(仅作用于本机 Go 环境,下载并安装gofr命令):
go install gofr.dev/cli/gofr@latest

安装后用gofr version确认命令可用。

另外,迁移最终要作用到一个真实数据源上。以 MySQL 为例,可参考 connecting-mysql 文档 启动本地数据库并配置configs/.env

docker run --name gofr-mysql -e MYSQL_ROOT_PASSWORD=root123 -e MYSQL_DATABASE=test_db -p 3306:3306 -d mysql:8.0.30
# configs/.env APP_NAME=test-service HTTP_PORT=8000 DB_HOST=localhost DB_USER=root DB_PASSWORD=root123 DB_NAME=test_db DB_PORT=3306 DB_DIALECT=mysql DB_CHARSET=utf8 #(optional)

GoFr 的数据迁移支持 MySQL、Postgres、Redis、ClickHouse 与 Cassandra,d.SQL覆盖 MySQL 和 PostgreSQL,migration.Datasource同时包含 Redis 等其他数据源。

生成迁移模板与 all.go 注册表

在包含go.mod的项目根目录下执行:

gofr migrate create -name=create_employee_table

-name参数是迁移名,生成文件时会作为时间戳之后的后缀。根据 gofr migrate create 参考文档,这条命令会生成一个迁移目录,其中包含两类文件:

  1. 一个带时间戳前缀的新迁移文件(文档示例为20250127152047_create_employee_table.go,实际前缀取决于执行命令的时刻),内容为预定义的模板:
package migrations import ( "gofr.dev/pkg/gofr/migration" ) func create_employee_table() migration.Migrate { return migration.Migrate{ UP: func(d migration.Datasource) error { // write your migrations here return nil }, } }
  1. 一个自动生成的all.go,作为所有迁移的注册表:
// This is auto-generated file using 'gofr migrate' tool. DO NOT EDIT. package migrations import ( "gofr.dev/pkg/gofr/migration" ) func All() map[int64]migration.Migrate { return map[int64]migration.Migrate { 20250127152047: create_employee_table(), } }

关于命名,handling-data-migrations 文档建议在项目根目录维护一个migrations目录,并且每个迁移文件按创建时间的YYYYMMDDHHMMSS格式编号——这正是gofr migrate create自动生成的时间戳前缀。该格式可以防止编号冲突,并保证迁移在不同文件系统上排序一致。

需要特别注意:all.go头部标注了DO NOT EDIT,它是gofr migrate工具自动维护的。每次执行gofr migrate create时,新迁移会以「时间戳 → 迁移函数」的形式追加进All()返回的 map,你不需要手动改这个文件。

在模板中编写迁移逻辑

模板里的UP函数接收一个migration.Datasource,按文档给出的 SQL 示例填充:在 handling-data-migrations 文档中,文件名20240226153000_create_employee_table.go对应如下实现:

package migrations import "gofr.dev/pkg/gofr/migration" const createTable = `CREATE TABLE IF NOT EXISTS employee ( id int not null primary key, name varchar(50) not null, gender varchar(6) not null, contact_number varchar(10) not null );` func createEmployeeTable() migration.Migrate { return migration.Migrate{ UP: func(d migration.Datasource) error { _, err := d.SQL.Exec(createTable) if err != nil { return err } return nil }, } }

几条来自文档的约束:

  • 所有迁移都在事务内执行;
  • 使用 MySQL 时,DDL 语句会隐式提交,因此 DDL 中要用IF EXISTS/IF NOT EXISTS保证可重放性;
  • 目前只支持UP方法,没有回滚迁移。

文档还建议按**功能(feature)**而不是按单张表或单条操作来组织迁移:同一个功能涉及的建表、加列等操作应放进同一个迁移函数里,这样回滚一个功能只需回滚一条迁移记录。仓库中的 examples/using-migrations/migrations/all.go 展示了多个迁移共存的注册表形态:

func All() map[int64]migration.Migrate { return map[int64]migration.Migrate { 1722507126: createTableEmployee(), 1722507180: addEmployeeInRedis(), } }

迁移按该 map 中 key 的升序执行,所以时间戳即执行顺序。

在 main.go 中接入迁移

按文档的初始化方式,把注册表交给 GoFr 应用:

package main import ( "gofr.dev/examples/using-migrations/migrations" "gofr.dev/pkg/gofr" ) func main() { // Create a new application a := gofr.New() // Add migrations to run a.Migrate(migrations.All()) // Run the application a.Run() }

其中migrations包的导入路径要换成你自己项目中migrations目录对应的模块路径。a.Migrate(...)之后 GoFr 在启动阶段执行迁移,a.Run()之前迁移已经完成。

运行并验证迁移是否成功

以仓库中的 using-migrations 示例 为参照,先启动 MySQL(该示例用MYSQL_ROOT_PASSWORD=password、数据库test、端口映射 2001:3306 的镜像),然后在示例目录下执行:

go run main.go

运行后,文档给出的成功日志形如(GoFr 默认向 stdout 输出结构化 JSON):

{"level":"INFO","time":"2024-02-26T16:55:46.123456789+05:30","message":"Migration 20240226153000 ran successfully","gofrVersion":"v1.56.4"}

以上为文档示例输出,timegofrVersion字段值会随实际运行环境变化,判断成功的依据是出现ran successfully的迁移消息。

GoFr 还会在数据库内部维护迁移记录,用于追踪哪些迁移已经执行过、确保从未运行过的迁移才执行:

  • SQL(MySQL/PostgreSQL):记录存于gofr_migrations表,字段为version(bigint)、method(varchar(4))、start_time(timestamp)、duration(bigint)。
  • Redis:记录存于名为gofr_migrations的 Redis Hash,key 是版本号(如20240226153000),value 为包含methodstartTimeduration的 JSON。

因此第二次启动同一服务时,已经ran successfully的迁移不会再次执行。

限制与注意事项

  • all.gogofr migrate工具自动维护,不要手工编辑;新增迁移一律通过gofr migrate create -name=<migration-name>生成。
  • 迁移只支持UP方向,文档明确说明"only method UP is supported",不存在框架级的 DOWN 回滚。
  • migration.DatasourceSQL面向 MySQL/PostgreSQL;RedisPubSubClickhouseCassandraElasticsearch等数据源的迁移写法不同,且 Cassandra 不保证单条 DML 的原子性(需要时用NewBatch/BatchQuery/ExecuteBatch做批量操作)。
  • 多实例部署时 GoFr 会用分布式锁自动协调迁移(SQL 用gofr_migration_locks表,Redis 用SETNX,锁 TTL 15 秒),无需改代码;单实例部署行为不变。
  • Redis Streams 模式下使用 PubSub 迁移,订阅要求配置 Consumer Group ID,缺失会导致订阅报错。

下一步

  • 迁移的完整写法(多数据源、PubSub、按功能组织)见 handling-data-migrations 文档;
  • CLI 其他子命令(gofr initgofr storegofr wrap grpc)见 GoFr CLI 参考;
  • 可运行的迁移示例代码见 examples/using-migrations/main.go 与 examples/using-migrations/migrations/1722507126_create_employee_table.go。

【免费下载链接】gofrAn opinionated GoLang framework for accelerated microservice development. Built in support for databases and observability.项目地址: https://gitcode.com/GitHub_Trending/go/gofr

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询