Dbmate 是一个数据库迁移工具,可以使您的数据库架构在多个开发人员和生产服务器之间保持同步。
它是一个独立的命令行工具,可与 Go、Node.js、Python、Ruby、PHP、Rust、C++ 或用于编写数据库支持的应用程序的任何其他语言或框架一起使用。如果您用不同的语言编写多个服务,并且希望使用一致的开发工具保持一定的理智,这尤其有用。
有关 dbmate 和其他流行的数据库架构迁移工具之间的比较,请参阅替代方案。
schema.sql
文件以轻松比较 git 中的架构更改DATABASE_URL
),或在命令行上指定.env
文件读取环境变量国家公共管理
使用 NPM 安装:
npm install --save-dev dbmate
npx dbmate --help
macOS
使用自制程序安装:
brew install dbmate
dbmate --help
Linux
直接安装二进制文件:
sudo curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64
sudo chmod +x /usr/local/bin/dbmate
/usr/local/bin/dbmate --help
视窗
使用勺子安装
scoop install dbmate
dbmate -- help
码头工人
Docker 镜像发布到 GitHub 容器注册表 ( ghcr.io/amacneil/dbmate
)。
请记住设置--network=host
或查看此评论以获取有关在 docker 网络中使用 dbmate 的更多提示):
docker run --rm -it --network=host ghcr.io/amacneil/dbmate --help
如果您希望创建或应用迁移,则需要使用 Docker 的绑定安装功能使本地工作目录 ( pwd
) 在 dbmate 容器内可用:
docker run --rm -it --network=host -v " $( pwd ) /db:/db " ghcr.io/amacneil/dbmate new create_users_table
dbmate --help # print usage help
dbmate new # generate a new migration file
dbmate up # create the database (if it does not already exist) and run any pending migrations
dbmate create # create the database
dbmate drop # drop the database
dbmate migrate # run any pending migrations
dbmate rollback # roll back the most recent migration
dbmate down # alias for rollback
dbmate status # show the status of all migrations (supports --exit-code and --quiet)
dbmate dump # write the database schema.sql file
dbmate load # load schema.sql file to the database
dbmate wait # wait for the database server to become available
以下选项适用于所有命令。您必须按照dbmate [global options] command [command options]
顺序使用命令行参数。大多数选项也可以通过环境变量进行配置(并从.env
文件加载,这有助于在团队成员之间共享配置)。
--url, -u "protocol://host:port/dbname"
- 直接指定数据库 url。 (环境: DATABASE_URL
)--env, -e "DATABASE_URL"
- 指定一个环境变量来读取数据库连接 URL。--env-file ".env"
- 指定要加载的备用环境变量文件。--migrations-dir, -d "./db/migrations"
- 保存迁移文件的位置。 (环境: DBMATE_MIGRATIONS_DIR
)--migrations-table "schema_migrations"
- 记录迁移的数据库表。 (env: DBMATE_MIGRATIONS_TABLE
)--schema-file, -s "./db/schema.sql"
- 保存 schema.sql 文件的路径。 (环境: DBMATE_SCHEMA_FILE
)--no-dump-schema
- 迁移/回滚时不要自动更新 schema.sql 文件(env: DBMATE_NO_DUMP_SCHEMA
)--strict
- 如果迁移不按顺序应用则失败(env: DBMATE_STRICT
)--wait
- 在执行后续命令之前等待数据库变得可用(env: DBMATE_WAIT
)--wait-timeout 60s
- --wait 标志超时(env: DBMATE_WAIT_TIMEOUT
) 默认情况下,Dbmate 使用DATABASE_URL
环境变量来定位您的数据库。如果您正在编写一个十二因素应用程序,则应该将所有连接字符串存储在环境变量中。
为了使开发变得容易,dbmate 在当前目录中查找.env
文件,并将其中列出的任何变量视为在当前环境中指定的变量(但是,现有环境变量优先)。
如果您还没有.env
文件,请创建一个并添加您的数据库连接 URL:
$ cat .env
DATABASE_URL= " postgres://[email protected]:5432/myapp_development?sslmode=disable "
DATABASE_URL
应按以下格式指定:
protocol://username:password@host:port/database_name?options
protocol
必须是mysql
、 postgres
、 postgresql
、 sqlite
、 sqlite3
、 clickhouse
之一username
和password
必须经过 URL 编码(如果使用特殊字符将会出现错误)host
可以是主机名或 IP 地址options
是特定于驱动程序的(如果您想使用这些选项,请参阅底层 Go SQL 驱动程序) Dbmate 还可以从不同的环境变量加载连接 URL。例如,在运行测试套件之前,您可能希望删除并重新创建测试数据库。一种简单的方法是将测试数据库连接 URL 存储在TEST_DATABASE_URL
环境变量中:
$ cat .env
DATABASE_URL= " postgres://[email protected]:5432/myapp_dev?sslmode=disable "
TEST_DATABASE_URL= " postgres://[email protected]:5432/myapp_test?sslmode=disable "
然后,您可以在测试脚本(Makefile 或类似文件)中指定此环境变量:
$ dbmate -e TEST_DATABASE_URL drop
Dropping: myapp_test
$ dbmate -e TEST_DATABASE_URL --no-dump-schema up
Creating: myapp_test
Applying: 20151127184807_create_users_table.sql
Applied: 20151127184807_create_users_table.sql in 123µs
或者,您可以直接在命令行上指定 url:
$ dbmate -u " postgres://[email protected]:5432/myapp_test?sslmode=disable " up
使用dbmate -e TEST_DATABASE_URL
相对于dbmate -u $TEST_DATABASE_URL
的唯一优点是前者利用 dbmate 的自动.env
文件加载。
连接到 Postgres 时,您可能需要将sslmode=disable
选项添加到连接字符串中,因为 dbmate 默认情况下需要 TLS 连接(某些其他框架/语言默认情况下允许未加密的连接)。
DATABASE_URL= " postgres://username:[email protected]:5432/database_name?sslmode=disable "
可以指定socket
或host
参数以通过unix套接字进行连接(注意:仅指定目录):
DATABASE_URL= " postgres://username:password@/database_name?socket=/var/run/postgresql "
search_path
参数可用于在应用迁移时指定当前模式,以及 dbmate 的schema_migrations
表。如果模式不存在,则会自动创建。如果传递多个以逗号分隔的架构,第一个架构将用于schema_migrations
表。
DATABASE_URL= " postgres://username:[email protected]:5432/database_name?search_path=myschema "
DATABASE_URL= " postgres://username:[email protected]:5432/database_name?search_path=myschema,public "
DATABASE_URL= " mysql://username:[email protected]:3306/database_name "
可以指定一个socket
参数来通过unix套接字进行连接:
DATABASE_URL= " mysql://username:password@/database_name?socket=/var/run/mysqld/mysqld.sock "
SQLite 数据库存储在文件系统上,因此您不需要指定主机。默认情况下,文件是相对于当前目录的。例如,以下命令将在./db/database.sqlite3
创建一个数据库:
DATABASE_URL= " sqlite:db/database.sqlite3 "
要指定绝对路径,请向路径添加正斜杠。以下将在/tmp/database.sqlite3
创建一个数据库:
DATABASE_URL= " sqlite:/tmp/database.sqlite3 "
DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name "
要使用 ClickHouse 集群,可以提供 4 个连接查询参数:
on_cluster
- 指示使用集群语句和复制的迁移表。 (默认值: false
)如果未提供此参数,则忽略其他与集群相关的查询参数。 DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster "
DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster=true "
cluster_macro
(可选)- 用于 ON CLUSTER 语句和复制的迁移表引擎 Zookeeper 路径的宏值。 (默认值: {cluster}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&cluster_macro={my_cluster} "
replica_macro
(可选)- 用于复制的迁移表引擎中的副本名称的宏值。 (默认值: {replica}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&replica_macro={my_replica} "
zoo_path
(可选) - ClickHouse/Zoo Keeper 中表迁移的路径。 (默认: /clickhouse/tables/<cluster_macro>/{table}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&zoo_path=/zk/path/tables "
查看其他支持的连接选项。
连接到 GCP 中的实际 BigQuery 时,请遵循以下DATABASE_URL
格式:
bigquery://projectid/location/dataset
projectid
(必填)- 项目 ID
dataset
(必填)- 项目内的数据集名称
location
(可选)- 创建数据集的位置
注意:按照此文档了解如何设置GOOGLE_APPLICATION_CREDENTIALS
环境变量以进行正确的身份验证
如果尝试连接到自定义端点(例如 BigQuery Emulator),请遵循以下格式
bigquery://host:port/projectid/location/dataset?disable_auth=true
disable_auth
(可选)- 传递true
以跳过身份验证,仅用于测试和连接到模拟器。
Spanner 支持当前仅限于使用 PostgreSQL Dialect 的数据库,必须在创建数据库时选择该方言。对于未来支持 GoogleSQL 的 Spanner,请参阅此讨论。
具有 Postgres 接口的 Spanner 要求 PGAdapter 正在运行。对DATABASE_URL
使用以下格式,并将主机和端口设置为 PGAdapter 运行的位置:
DATABASE_URL= " spanner-postgres://127.0.0.1:5432/database_name?sslmode=disable "
请注意,指定用户名和密码不是必需的,因为身份验证由 PGAdapter 处理(如果指定,它们将被 PGAdapter 忽略)。
支持 postgres 驱动程序的其他选项。
Spanner 也不允许在显式事务内执行 DDL。因此,您必须在包含 DDL 的迁移上指定transaction:false
:
-- migrate:up transaction:false
CREATE TABLE ...
-- migrate:down transaction:false
DROP TABLE ...
当前不支持架构转储,因为pg_dump
使用 Spanner 未提供的函数。
要创建新的迁移,请运行dbmate new create_users_table
。您可以为迁移命名任何您喜欢的名称。这将在当前目录中创建一个文件db/migrations/20151127184807_create_users_table.sql
:
-- migrate:up
-- migrate:down
要编写迁移,只需将 SQL 添加到migrate:up
部分:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
email varchar ( 255 ) not null
);
-- migrate:down
注意:迁移文件以
[version]_[description].sql
格式命名。数据库中仅记录版本(定义为文件名中的所有前导数字字符),因此您可以安全地重命名迁移文件,而不会对其当前应用程序状态产生任何影响。
运行dbmate up
以运行任何挂起的迁移。
$ dbmate up
Creating: myapp_development
Applying: 20151127184807_create_users_table.sql
Applied: 20151127184807_create_users_table.sql in 123µs
Writing: ./db/schema.sql
注意:如果数据库尚不存在,
dbmate up
将创建该数据库(假设当前用户具有创建数据库的权限)。如果您想在不创建数据库的情况下运行迁移,请运行dbmate migrate
。
待处理的迁移始终按数字顺序应用。但是,如果迁移是独立提交的,则 dbmate 不会阻止乱序应用迁移(例如:如果开发人员已经在一个分支上工作了很长时间,并且提交了一个版本号低于其他版本号的迁移)应用的迁移,dbmate 将简单地应用待处理的迁移)。更详细的解释请参见#159。
默认情况下,dbmate 不知道如何回滚迁移。在开发过程中,能够将数据库恢复到以前的状态通常很有用。要实现此目的,请实现migrate:down
部分:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
email varchar ( 255 ) not null
);
-- migrate:down
drop table users;
运行dbmate rollback
以回滚最近的迁移:
$ dbmate rollback
Rolling back: 20151127184807_create_users_table.sql
Rolled back: 20151127184807_create_users_table.sql in 123µs
Writing: ./db/schema.sql
dbmate 支持以key:value
对的形式传递给迁移块的选项。支持的选项列表:
transaction
交易
如果您不想在事务内运行 SQL,则transaction
很有用:
-- migrate:up transaction:false
ALTER TYPE colors ADD VALUE ' orange ' AFTER ' red ' ;
如果您的数据库支持, transaction
将默认为true
。
如果您的项目使用 Docker 开发环境,则在运行迁移或单元测试时可能会遇到数据库未立即准备就绪的问题。这可能是由于数据库服务器刚刚启动。
一般来说,您的应用程序应该能够适应启动时没有工作数据库连接的情况。但是,出于运行迁移或单元测试的目的,这是不切实际的。 wait
命令允许您暂停脚本或其他应用程序,直到数据库可用,从而避免这种情况。 Dbmate 每秒都会尝试连接到数据库服务器,最多 60 秒。
如果数据库可用, wait
将不会返回任何输出:
$ dbmate wait
如果数据库不可用, wait
将阻塞,直到数据库可用:
$ dbmate wait
Waiting for database....
如果您有时会看到由于数据库尚未准备就绪而导致的失败,您还可以将--wait
标志与其他命令一起使用:
$ dbmate --wait up
Waiting for database....
Creating: myapp_development
您可以使用--wait-timeout
自定义超时(默认 60 秒)。如果数据库仍然不可用,该命令将返回错误:
$ dbmate --wait-timeout=5s wait
Waiting for database.....
Error: unable to connect to database: dial tcp 127.0.0.1:5432: connect: connection refused
请注意, wait
命令不会验证您指定的数据库是否存在,只会验证服务器是否可用并准备就绪(因此如果数据库服务器可用,但您的数据库尚未创建,则会返回成功)。
当您运行up
、 migrate
或rollback
命令时,dbmate 将自动创建一个./db/schema.sql
文件,其中包含数据库模式的完整表示。 Dbmate 会为您保持此文件最新,因此您不应手动编辑它。
建议将此文件签入源代码管理,以便您可以轻松查看提交或拉取请求中架构的更改。当您想要快速加载数据库架构而不按顺序运行每个迁移(例如在测试工具中)时,也可以使用此文件。但是,如果您不想保存此文件,可以将其添加到.gitignore
中,或传递--no-dump-schema
命令行选项。
要转储schema.sql
文件而不执行任何其他操作,请运行dbmate dump
。与其他 dbmate 操作不同,此命令依赖于 PATH 中可用的相应pg_dump
、 mysqldump
或sqlite3
命令。如果这些工具不可用,dbmate 将在up
、 migrate
或rollback
操作期间默默地跳过架构转储步骤。您可以通过运行dbmate dump
并查看输出来诊断问题:
$ dbmate dump
exec: " pg_dump " : executable file not found in $PATH
在 Ubuntu 或 Debian 系统上,您可以通过分别安装postgresql-client
、 mysql-client
或sqlite3
来修复此问题。确保您安装的软件包版本大于或等于数据库服务器上运行的版本。
注意:
schema.sql
文件将包含数据库的完整架构,即使某些表或列是在 dbmate 迁移之外创建的。
Dbmate 被设计为用作任何语言或框架的 CLI,但它也可以用作 Go 应用程序中的库。
这是一个简单的例子。记得导入你需要的驱动!
package main
import (
"net/url"
"github.com/amacneil/dbmate/v2/pkg/dbmate"
_ "github.com/amacneil/dbmate/v2/pkg/driver/sqlite"
)
func main () {
u , _ := url . Parse ( "sqlite:foo.sqlite3" )
db := dbmate . New ( u )
err := db . CreateAndMigrate ()
if err != nil {
panic ( err )
}
}
有关更多选项,请参阅参考文档。
可以使用 Go 的嵌入功能将迁移嵌入到您的应用程序二进制文件中。
使用db.FS
指定用于读取迁移的文件系统:
package main
import (
"embed"
"fmt"
"net/url"
"github.com/amacneil/dbmate/v2/pkg/dbmate"
_ "github.com/amacneil/dbmate/v2/pkg/driver/sqlite"
)
//go:embed db/migrations/*.sql
var fs embed. FS
func main () {
u , _ := url . Parse ( "sqlite:foo.sqlite3" )
db := dbmate . New ( u )
db . FS = fs
fmt . Println ( "Migrations:" )
migrations , err := db . FindMigrations ()
if err != nil {
panic ( err )
}
for _ , m := range migrations {
fmt . Println ( m . Version , m . FilePath )
}
fmt . Println ( " n Applying..." )
err = db . CreateAndMigrate ()
if err != nil {
panic ( err )
}
}
迁移文件非常简单,默认存储在./db/migrations
中。您可以通过运行dbmate new create_users
创建一个名为[date]_create_users.sql
的新迁移文件。这是一个例子:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
);
-- migrate:down
drop table if exists users;
向上和向下迁移都存储在同一个文件中,以便于编辑。即使您选择不实施向下迁移,向上和向下指令都是必需的。
当您应用迁移时,dbmate 仅存储版本号,而不存储内容,因此您应该始终在修改迁移内容之前回滚迁移。因此,只要保持版本号不变,您就可以安全地重命名迁移文件,而不会影响其应用状态。
默认情况下,架构文件写入./db/schema.sql
。它是数据库架构的完整转储,包括任何应用的迁移以及您所做的任何其他修改。
应将此文件签入源代码管理,以便您可以轻松比较迁移的差异。您可以使用架构文件快速恢复数据库,而无需运行所有迁移。
Dbmate 将每个应用的迁移的记录存储在名为schema_migrations
的表中。如果该表尚不存在,系统会自动为您创建该表。
该表非常简单:
CREATE TABLE IF NOT EXISTS schema_migrations (
version VARCHAR ( 255 ) PRIMARY KEY
)
您可以使用--migrations-table
标志或DBMATE_MIGRATIONS_TABLE
环境变量自定义此表的名称。
为什么需要另一个数据库架构迁移工具? Dbmate 受到许多其他工具的启发,主要是 Active Record 迁移,其目标是配置简单、独立于语言和框架。下面是 dbmate 和其他流行迁移工具的比较。
数据库伙伴 | 鹅 | sql-迁移 | golang-迁移 | 活动记录 | 续集 | 飞行路线 | 斯奇奇 | |
---|---|---|---|---|---|---|---|---|
特征 | ||||||||
纯 SQL 迁移文件 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
支持创建和删除数据库 | ✅ | ✅ | ||||||
支持保存模式转储文件 | ✅ | ✅ | ||||||
时间戳版本控制的迁移文件 | ✅ | ✅ | ✅ | ✅ | ✅ | |||
自定义架构迁移表 | ✅ | ✅ | ✅ | ✅ | ||||
能够等待数据库准备就绪 | ✅ | |||||||
从环境变量加载的数据库连接字符串 | ✅ | ✅ | ||||||
自动加载.env文件 | ✅ | |||||||
没有单独的配置文件 | ✅ | ✅ | ✅ | ✅ | ✅ | |||
独立于语言/框架 | ✅ | ✅ | ✅ | ✅ | ✅ | |||
司机 | ||||||||
PostgreSQL | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
MySQL | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
SQLite | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
点击屋 | ✅ | ✅ | ✅ | ✅ |
如果您发现此表中有任何不准确之处,请提出更改。
Dbmate 是用 Go 编写的,欢迎请求请求。
使用 docker compose 对真实数据库运行测试。要构建 docker 映像并运行测试:
$ make docker-all
启动开发外壳:
$ make docker-sh