pressly/goose
GitHub: pressly/goose
一个支持 SQL 与 Go 函数的数据库迁移工具,用于安全、可追溯地管理数据库架构变更。
Stars: 10514 | Forks: 638
# goose
[](https://github.com/pressly/goose/actions/workflows/ci.yaml)
[](https://pkg.go.dev/github.com/pressly/goose/v3)
[](https://goreportcard.com/report/github.com/pressly/goose/v3)
Goose 是一个数据库迁移工具。它既支持命令行也支持库的形式使用。
通过创建增量的 SQL 变更或 Go 函数来管理你的 **数据库架构(schema)**。
#### 功能特性
- 支持多种数据库:
- PostgreSQL、MySQL、Spanner、SQLite、YDB、ClickHouse、MSSQL、Vertica,以及
更多。
- 支持以普通函数形式编写 Go 迁移。
- 支持 [嵌入式](https://pkg.go.dev/embed/) 迁移。
- 无序迁移。
- 数据填充(Seeding)。
- 在 SQL 迁移中支持环境变量替换。
- ……还有更多。
# 安装
```
go install github.com/pressly/goose/v3/cmd/goose@latest
```
这会将 `goose` 二进制文件安装到你的 `$GOPATH/bin` 目录。
二进制文件过大?可以通过排除不需要的数据库驱动来构建精简版本:
```
go build -tags='no_postgres no_mysql no_sqlite3 no_ydb' -o goose ./cmd/goose
# Available build tags:
# no_clickhouse no_libsql no_mssql no_mysql
# no_postgres no_sqlite3 no_vertica no_ydb
```
macOS 用户可以通过 [Homebrew
Formulae](https://formulae.brew.sh/formula/goose#default) 安装 `goose`:
```
brew install goose
```
更多细节请参考 [安装文档](https://pressly.github.io/goose/installation/)。
# 用法
点击显示
```
Usage: goose DRIVER DBSTRING [OPTIONS] COMMAND
or
Set environment key
GOOSE_DRIVER=DRIVER
GOOSE_DBSTRING=DBSTRING
GOOSE_MIGRATION_DIR=MIGRATION_DIR
Usage: goose [OPTIONS] COMMAND
Drivers:
postgres
mysql
sqlite3
spanner
mssql
redshift
tidb
clickhouse
ydb
starrocks
turso
Examples:
goose sqlite3 ./foo.db status
goose sqlite3 ./foo.db create init sql
goose sqlite3 ./foo.db create add_some_column sql
goose sqlite3 ./foo.db create fetch_user_data go
goose sqlite3 ./foo.db up
goose postgres "user=postgres dbname=postgres sslmode=disable" status
goose mysql "user:password@/dbname?parseTime=true" status
goose spanner "projects/project/instances/instance/databases/database" status
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
goose tidb "user:password@/dbname?parseTime=true" status
goose mssql "sqlserver://user:password@hostname:1433?database=master" status
goose clickhouse "tcp://127.0.0.1:9000" status
goose ydb "grpcs://localhost:2135/local?go_query_mode=scripting&go_fake_tx=scripting&go_query_bind=declare,numeric" status
goose starrocks "user:password@/dbname?parseTime=true&interpolateParams=true" status
GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose status
GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose create init sql
GOOSE_DRIVER=postgres GOOSE_DBSTRING="user=postgres dbname=postgres sslmode=disable" goose status
GOOSE_DRIVER=mysql GOOSE_DBSTRING="user:password@/dbname" goose status
GOOSE_DRIVER=redshift GOOSE_DBSTRING="postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" goose status
GOOSE_DRIVER=clickhouse GOOSE_DBSTRING="clickhouse://user:password@qwerty.clickhouse.cloud:9440/dbname?secure=true&skip_verify=false" goose status
Options:
-allow-missing
applies missing (out-of-order) migrations
-certfile string
file path to root CA's certificates in pem format (only support on mysql)
-dir string
directory with migration files (default ".", can be set via the GOOSE_MIGRATION_DIR env variable).
-h print help
-no-color
disable color output (NO_COLOR env variable supported)
-no-versioning
apply migration commands with no versioning, in file order, from directory pointed to
-s use sequential numbering for new migrations
-ssl-cert string
file path to SSL certificates in pem format (only support on mysql)
-ssl-key string
file path to SSL key in pem format (only support on mysql)
-table string
migrations table name (default "goose_db_version"). If you use a schema that is not `public`, you should set `schemaname.goose_db_version` when running commands.
-timeout duration
maximum allowed duration for queries to run; e.g., 1h13m
-v enable verbose mode
-version
print version
Commands:
up Migrate the DB to the most recent version available
up-by-one Migrate the DB up by 1
up-to VERSION Migrate the DB to a specific VERSION
down Roll back the version by 1
down-to VERSION Roll back to a specific VERSION
redo Re-run the latest migration
reset Roll back all migrations
status Dump the migration status for the current DB
version Print the current version of the database
create NAME [sql|go] Creates new migration file with the current timestamp
fix Apply sequential ordering to migrations
validate Check migration files without running them
```
常用命令:
[create](#create) • [up](#up) • [up-to](#up-to) • [down](#down) • [down-to](#down-to) • [status](#status) • [version](#version)
## create
创建新的 SQL 迁移文件。
```
$ goose create add_some_column sql
$ Created new file: 20170506082420_add_some_column.sql
$ goose -s create add_some_column sql
$ Created new file: 00001_add_some_column.sql
```
编辑新创建的文件以定义迁移行为。
你也可以创建一个 Go 迁移,如果随后使用你自己的 goose
二进制文件调用它:
```
$ goose create fetch_user_data go
$ Created new file: 20170506082421_fetch_user_data.go
```
## up
应用所有可用的迁移。
```
$ goose up
$ OK 001_basics.sql
$ OK 002_next.sql
$ OK 003_and_again.go
```
## up-to
迁移到指定版本。
```
$ goose up-to 20170506082420
$ OK 20170506082420_create_table.sql
```
## up-by-one
从当前版本迁移一步。
```
$ goose up-by-one
$ OK 20170614145246_change_type.sql
```
## down
回滚当前版本的一条迁移。
```
$ goose down
$ OK 003_and_again.go
```
## down-to
回滚到指定版本。
```
$ goose down-to 20170506082527
$ OK 20170506082527_alter_column.sql
```
或者,回滚所有迁移(请小心!):
```
$ goose down-to 0
```
## status
打印所有迁移的状态:
```
$ goose status
$ Applied At Migration
$ =======================================
$ Sun Jan 6 11:25:03 2013 -- 001_basics.sql
$ Sun Jan 6 11:25:03 2013 -- 002_next.sql
$ Pending -- 003_and_again.go
```
注意:对于 MySQL,需要启用 [parseTime 标志](https://github.com/go-sql-driver/mysql#parsetime)。
注意:对于 MySQL
[`multiStatements`](https://github.com/go-sql-driver/mysql?tab=readme-ov-file#multistatements) 必须
启用。当在单个 sql 文件中使用分号分隔多条查询时,这是必需的。
## version
打印当前数据库版本:
```
$ goose version
$ goose: version 002
```
# 环境变量
如果你更倾向于使用环境变量,而不是将驱动和数据库字符串作为参数传递,可以设置以下环境变量:
**1. 通过环境变量:**
```
export GOOSE_DRIVER=DRIVER
export GOOSE_DBSTRING=DBSTRING
export GOOSE_MIGRATION_DIR=MIGRATION_DIR
export GOOSE_TABLE=TABLENAME
```
**2. 通过 `.env` 文件及对应变量。`.env` 文件示例**:
```
GOOSE_DRIVER=postgres
GOOSE_DBSTRING=postgres://admin:admin@localhost:5432/admin_db
GOOSE_MIGRATION_DIR=./migrations
GOOSE_TABLE=custom.goose_migrations
```
默认启用从 `.env` 文件加载。若要禁用此功能,请设置 `-env=none` 标志。
如果要从特定文件加载,请设置 `-env` 标志为文件路径。
有关环境变量的更多细节,请参考[官方文档](https://pressly.github.io/goose/documentation/environment-variables/)。
# 迁移
goose 支持 SQL 或 Go 编写的迁移。
## SQL 迁移
一个示例 SQL 迁移如下:
```
-- +goose Up
CREATE TABLE post (
id int NOT NULL,
title text,
body text,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE post;
```
每个迁移文件必须恰好包含一个 `-- +goose Up` 注释。`-- +goose Down` 注释是可选的。如果文件同时包含两者,`-- +goose Up` 注释 **必须** 排在前面。
请注意注释中的标记。`-- +goose Up` 之后的语句将在正向迁移中执行,`-- +goose Down` 之后的语句将在回滚中执行。
默认情况下,所有迁移都在事务中运行。但像 `CREATE DATABASE` 这样的语句无法在事务中运行。你可以选择在迁移文件顶部添加 `-- +goose NO TRANSACTION` 来跳过该文件的事务。
此文件中的正向和回滚迁移都将无事务运行。
默认情况下,SQL 语句以分号分隔——实际上,查询语句必须以分号结尾才能被 goose 正确识别。
默认情况下,所有迁移都在 public 模式下运行。如果要使用其他模式,请使用表选项指定模式名称,例如 `-table='schemaname.goose_db_version`。
包含分号的复杂语句(如 PL/pgSQL)必须用 `-- +goose StatementBegin` 和 `-- +goose StatementEnd` 注释包裹,以便正确识别。例如:
```
-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN SELECT
'CREATE TABLE IF NOT EXISTS histories_'
|| TO_CHAR( d, 'YYYY_MM' )
|| ' ( CHECK( created_at >= timestamp '''
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|| ''' AND created_at < timestamp '''
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|| ''' ) ) inherits ( histories );'
FROM generate_series( $1, $2, '1 month' ) AS d
LOOP
EXECUTE create_query;
END LOOP; -- LOOP END
END; -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd
```
goose 支持在 SQL 迁移中通过注释进行环境变量替换。要启用此功能,请在希望应用替换的查询前使用 `-- +goose ENVSUB ON` 注释。
它会保持激活状态,直到遇到 `-- +goose ENVSUB OFF` 注释。
你可以在一个文件中多次使用这些注释。
此功能默认因向后兼容性而禁用。
对于 `PL/pgSQL` 函数或其他不需要替换的语句,请显式地将相关部分用注释包裹。例如,要排除对 `$$` 字符的转义:
```
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION test_func()
RETURNS void AS $$
-- +goose ENVSUB ON
BEGIN
RAISE NOTICE '${SOME_ENV_VAR}';
END;
-- +goose ENVSUB OFF
$$ LANGUAGE plpgsql;
-- +goose StatementEnd
```
## 嵌入式 SQL 迁移
Go 1.16 引入了新特性:[编译时嵌入](https://pkg.go.dev/embed/) 文件到二进制中,以及对应的 [文件系统抽象](https://pkg.go.dev/io/fs/)。
此特性仅适用于应用现有迁移。修改操作(如 `fix` 和 `create`)将继续在操作系统文件系统上运行,即使使用了嵌入式文件。
这是预期行为,因为 `io/fs` 接口只允许只读访问。
请确保配置正确的 SQL 方言,可参考 [dialect.go](./dialect.go) 支持的 SQL 方言。
示例用法,假设 SQL 迁移文件位于 `migrations` 目录:
```
package main
import (
"database/sql"
"embed"
"github.com/pressly/goose/v3"
)
//go:embed migrations/*.sql
var embedMigrations embed.FS
func main() {
var db *sql.DB
// setup database
goose.SetBaseFS(embedMigrations)
if err := goose.SetDialect("postgres"); err != nil {
panic(err)
}
if err := goose.Up(db, "migrations"); err != nil {
panic(err)
}
// run app
}
```
注意我们将 `"migrations"` 作为 `Up` 的目录参数,因为嵌入会保存目录结构。
## Go 迁移
1. 创建你自己的 goose 二进制文件,参考 [示例](./examples/go-migrations)
2. 导入 `github.com/pressly/goose`
3. 注册你的迁移函数
4. 将你的 `migrations` 包包含在 Go 构建中:在 `main.go` 中使用 `import _ "github.com/me/myapp/migrations"`
5. 运行 goose 命令,例如 `goose.Up(db *sql.DB, dir string)`
一个 [示例 Go 迁移文件 0002_users_add_email.go](./examples/go-migrations/00002_rename_root.go)
看起来像这样:
```
package migrations
import (
"database/sql"
"github.com/pressly/goose/v3"
)
func init() {
goose.AddMigration(Up, Down)
}
func Up(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
if err != nil {
return err
}
return nil
}
func Down(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
if err != nil {
return err
}
return nil
}
```
请注意,Go 迁移文件必须以数字开头,后跟下划线,且不能以 `*_test.go` 结尾。
# 混合版本控制
请先阅读 [版本问题](https://github.com/pressly/goose/issues/63#issuecomment-428681694)。
默认情况下,如果尝试应用缺失的(无序)迁移,goose 会报错。
但如果你希望应用这些缺失的迁移,可以给 goose 加上 `-allow-missing` 标志,或者在使用库时提供函数选项 `goose.WithAllowMissing()` 给 Up、UpTo 或 UpByOne。
不过,我们强烈建议采用混合版本控制方法,结合使用时间戳和顺序编号。在开发过程中创建的迁移使用时间戳,而在生产环境中运行的则使用顺序版本。我们相信这种方法能防止团队开发时版本冲突的问题。
为了帮助你采用这种方法,`create` 将使用当前时间戳作为迁移版本。
当你准备在生产环境中部署迁移时,我们还提供了一个有用的 `fix` 命令,可以将迁移转换为顺序排列,同时保留时间戳顺序。我们建议在 CI 流水线中运行 `fix`,并且仅在迁移准备生产部署时运行。
## 致谢
Gopher 吉祥物由 [Renée French](https://reneefrench.blogspot.com/) 设计 / [CC
3.0.](https://creativecommons.org/licenses/by/3.0/)。更多信息请参考 [Go
博客](https://go.dev/blog/gopher)。由 Ellen 改编。
## 许可证
根据 [MIT 许可证](./LICENSE) 授权。
[](https://github.com/pressly/goose/actions/workflows/ci.yaml)
[](https://pkg.go.dev/github.com/pressly/goose/v3)
[](https://goreportcard.com/report/github.com/pressly/goose/v3)
Goose 是一个数据库迁移工具。它既支持命令行也支持库的形式使用。
通过创建增量的 SQL 变更或 Go 函数来管理你的 **数据库架构(schema)**。
#### 功能特性
- 支持多种数据库:
- PostgreSQL、MySQL、Spanner、SQLite、YDB、ClickHouse、MSSQL、Vertica,以及
更多。
- 支持以普通函数形式编写 Go 迁移。
- 支持 [嵌入式](https://pkg.go.dev/embed/) 迁移。
- 无序迁移。
- 数据填充(Seeding)。
- 在 SQL 迁移中支持环境变量替换。
- ……还有更多。
# 安装
```
go install github.com/pressly/goose/v3/cmd/goose@latest
```
这会将 `goose` 二进制文件安装到你的 `$GOPATH/bin` 目录。
二进制文件过大?可以通过排除不需要的数据库驱动来构建精简版本:
```
go build -tags='no_postgres no_mysql no_sqlite3 no_ydb' -o goose ./cmd/goose
# Available build tags:
# no_clickhouse no_libsql no_mssql no_mysql
# no_postgres no_sqlite3 no_vertica no_ydb
```
macOS 用户可以通过 [Homebrew
Formulae](https://formulae.brew.sh/formula/goose#default) 安装 `goose`:
```
brew install goose
```
更多细节请参考 [安装文档](https://pressly.github.io/goose/installation/)。
# 用法
点击显示 goose help 输出
```
Usage: goose DRIVER DBSTRING [OPTIONS] COMMAND
or
Set environment key
GOOSE_DRIVER=DRIVER
GOOSE_DBSTRING=DBSTRING
GOOSE_MIGRATION_DIR=MIGRATION_DIR
Usage: goose [OPTIONS] COMMAND
Drivers:
postgres
mysql
sqlite3
spanner
mssql
redshift
tidb
clickhouse
ydb
starrocks
turso
Examples:
goose sqlite3 ./foo.db status
goose sqlite3 ./foo.db create init sql
goose sqlite3 ./foo.db create add_some_column sql
goose sqlite3 ./foo.db create fetch_user_data go
goose sqlite3 ./foo.db up
goose postgres "user=postgres dbname=postgres sslmode=disable" status
goose mysql "user:password@/dbname?parseTime=true" status
goose spanner "projects/project/instances/instance/databases/database" status
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
goose tidb "user:password@/dbname?parseTime=true" status
goose mssql "sqlserver://user:password@hostname:1433?database=master" status
goose clickhouse "tcp://127.0.0.1:9000" status
goose ydb "grpcs://localhost:2135/local?go_query_mode=scripting&go_fake_tx=scripting&go_query_bind=declare,numeric" status
goose starrocks "user:password@/dbname?parseTime=true&interpolateParams=true" status
GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose status
GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose create init sql
GOOSE_DRIVER=postgres GOOSE_DBSTRING="user=postgres dbname=postgres sslmode=disable" goose status
GOOSE_DRIVER=mysql GOOSE_DBSTRING="user:password@/dbname" goose status
GOOSE_DRIVER=redshift GOOSE_DBSTRING="postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" goose status
GOOSE_DRIVER=clickhouse GOOSE_DBSTRING="clickhouse://user:password@qwerty.clickhouse.cloud:9440/dbname?secure=true&skip_verify=false" goose status
Options:
-allow-missing
applies missing (out-of-order) migrations
-certfile string
file path to root CA's certificates in pem format (only support on mysql)
-dir string
directory with migration files (default ".", can be set via the GOOSE_MIGRATION_DIR env variable).
-h print help
-no-color
disable color output (NO_COLOR env variable supported)
-no-versioning
apply migration commands with no versioning, in file order, from directory pointed to
-s use sequential numbering for new migrations
-ssl-cert string
file path to SSL certificates in pem format (only support on mysql)
-ssl-key string
file path to SSL key in pem format (only support on mysql)
-table string
migrations table name (default "goose_db_version"). If you use a schema that is not `public`, you should set `schemaname.goose_db_version` when running commands.
-timeout duration
maximum allowed duration for queries to run; e.g., 1h13m
-v enable verbose mode
-version
print version
Commands:
up Migrate the DB to the most recent version available
up-by-one Migrate the DB up by 1
up-to VERSION Migrate the DB to a specific VERSION
down Roll back the version by 1
down-to VERSION Roll back to a specific VERSION
redo Re-run the latest migration
reset Roll back all migrations
status Dump the migration status for the current DB
version Print the current version of the database
create NAME [sql|go] Creates new migration file with the current timestamp
fix Apply sequential ordering to migrations
validate Check migration files without running them
```
点击展开支持的变量(点击此处展开):
- `${VAR}` 或 `$VAR` - 展开为环境变量 `VAR` 的值 - `${VAR:-default}` - 展开为环境变量 `VAR` 的值,若 `VAR` 未设置或为 null,则为 `default` - `${VAR-default}` - 展开为环境变量 `VAR` 的值,若 `VAR` 未设置则为 `default` - `${VAR?err_msg}` - 展开为环境变量 `VAR` 的值,若 `VAR` 未设置则打印 `err_msg` 并报错 - ~~`${VAR:?err_msg}` - 展开为环境变量 `VAR` 的值,或打印 `err_msg` 并报错(若 `VAR` 未设置或为 null)。~~ **此功能不支持** 更多细节请参考 [mfridman/interpolate](https://github.com/mfridman/interpolate?tab=readme-ov-file#supported-expansions)标签:CI, ClickHouse, EVTX分析, Goose, GoReport, Go函数迁移, Go语言, Go迁移函数, Homebrew, out-of-order迁移, PostgreSQL, Spanner, SQLite, SQL迁移, Vertica, YDB, 增量迁移, 多数据库支持, 多线程, 嵌入迁移, 库迁移, 数据库工具, 数据库迁移, 数据种子, 文档结构分析, 日志审计, 构建标签, 模式迁移, 环境变量替换, 程序破解