Dbmate é uma ferramenta de migração de banco de dados que manterá o esquema do seu banco de dados sincronizado entre vários desenvolvedores e servidores de produção.
É uma ferramenta de linha de comando independente que pode ser usada com Go, Node.js, Python, Ruby, PHP, Rust, C++ ou qualquer outra linguagem ou estrutura que você esteja usando para escrever aplicativos baseados em banco de dados. Isso é especialmente útil se você estiver escrevendo vários serviços em linguagens diferentes e quiser manter a sanidade com ferramentas de desenvolvimento consistentes.
Para uma comparação entre o dbmate e outras ferramentas populares de migração de esquema de banco de dados, consulte Alternativas.
schema.sql
para diferenciar facilmente as alterações do esquema no gitDATABASE_URL
por padrão) ou especificado na linha de comando.env
NPM
Instale usando NPM:
npm install --save-dev dbmate
npx dbmate --help
macOS
Instale usando o Homebrew:
brew install dbmate
dbmate --help
Linux
Instale o binário diretamente:
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
Windows
Instalar usando Scoop
scoop install dbmate
dbmate -- help
Docker
As imagens do Docker são publicadas no GitHub Container Registry ( ghcr.io/amacneil/dbmate
).
Lembre-se de definir --network=host
ou veja este comentário para obter mais dicas sobre como usar o dbmate com rede docker):
docker run --rm -it --network=host ghcr.io/amacneil/dbmate --help
Se desejar criar ou aplicar migrações, você precisará usar o recurso bind mount do Docker para disponibilizar seu diretório de trabalho local ( pwd
) dentro do contêiner 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
As opções a seguir estão disponíveis com todos os comandos. Você deve usar argumentos de linha de comando na ordem dbmate [global options] command [command options]
. A maioria das opções também pode ser configurada por meio de variáveis de ambiente (e carregadas do seu arquivo .env
, o que é útil para compartilhar a configuração entre os membros da equipe).
--url, -u "protocol://host:port/dbname"
- especifique o URL do banco de dados diretamente. (ambiente: DATABASE_URL
)--env, -e "DATABASE_URL"
- especifica uma variável de ambiente para ler o URL de conexão do banco de dados.--env-file ".env"
- especifique um(s) arquivo(s) de variáveis de ambiente alternativo(s) para carregar.--migrations-dir, -d "./db/migrations"
- onde manter os arquivos de migração. (ambiente: DBMATE_MIGRATIONS_DIR
)--migrations-table "schema_migrations"
- tabela de banco de dados para registrar migrações. (env: DBMATE_MIGRATIONS_TABLE
)--schema-file, -s "./db/schema.sql"
- um caminho para manter o arquivo schema.sql. (env: DBMATE_SCHEMA_FILE
)--no-dump-schema
- não atualiza automaticamente o arquivo schema.sql na migração/reversão (env: DBMATE_NO_DUMP_SCHEMA
)--strict
- falha se as migrações forem aplicadas fora de ordem (env: DBMATE_STRICT
)--wait
- espere que o banco de dados fique disponível antes de executar o comando subsequente (env: DBMATE_WAIT
)--wait-timeout 60s
- tempo limite para --wait sinalizador (env: DBMATE_WAIT_TIMEOUT
) O Dbmate localiza seu banco de dados usando a variável de ambiente DATABASE_URL
por padrão. Se você estiver escrevendo um aplicativo de doze fatores, deverá armazenar todas as cadeias de conexão em variáveis de ambiente.
Para facilitar o desenvolvimento, o dbmate procura um arquivo .env
no diretório atual e trata quaisquer variáveis listadas lá como se tivessem sido especificadas no ambiente atual (no entanto, as variáveis de ambiente existentes têm preferência).
Se você ainda não possui um arquivo .env
, crie um e adicione o URL de conexão do seu banco de dados:
$ cat .env
DATABASE_URL= " postgres://[email protected]:5432/myapp_development?sslmode=disable "
DATABASE_URL
deve ser especificado no seguinte formato:
protocol://username:password@host:port/database_name?options
protocol
deve ser mysql
, postgres
, postgresql
, sqlite
, sqlite3
, clickhouse
username
e password
devem ser codificados em URL (você receberá um erro se usar caracteres especiais)host
pode ser um nome de host ou endereço IPoptions
são específicas do driver (consulte os drivers Go SQL subjacentes se desejar usá-los) O Dbmate também pode carregar o URL de conexão de uma variável de ambiente diferente. Por exemplo, antes de executar seu conjunto de testes, você pode descartar e recriar o banco de dados de testes. Uma maneira fácil de fazer isso é armazenar o URL de conexão do banco de dados de teste na variável de ambiente 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 "
Você pode então especificar esta variável de ambiente em seu script de teste (Makefile ou similar):
$ 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
Alternativamente, você pode especificar o URL diretamente na linha de comando:
$ dbmate -u " postgres://[email protected]:5432/myapp_test?sslmode=disable " up
A única vantagem de usar dbmate -e TEST_DATABASE_URL
sobre dbmate -u $TEST_DATABASE_URL
é que o primeiro aproveita o carregamento automático do arquivo .env
do dbmate.
Ao conectar-se ao Postgres, pode ser necessário adicionar a opção sslmode=disable
à sua string de conexão, pois o dbmate por padrão requer uma conexão TLS (algumas outras estruturas/linguagens permitem conexões não criptografadas por padrão).
DATABASE_URL= " postgres://username:[email protected]:5432/database_name?sslmode=disable "
Um parâmetro socket
ou host
pode ser especificado para conectar através de um soquete unix (nota: especifique apenas o diretório):
DATABASE_URL= " postgres://username:password@/database_name?socket=/var/run/postgresql "
Um parâmetro search_path
pode ser usado para especificar o esquema atual ao aplicar migrações, bem como para a tabela schema_migrations
do dbmate. Se o esquema não existir, ele será criado automaticamente. Se vários esquemas separados por vírgula forem passados, o primeiro será usado para a tabela 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 "
Um parâmetro socket
pode ser especificado para conectar através de um soquete unix:
DATABASE_URL= " mysql://username:password@/database_name?socket=/var/run/mysqld/mysqld.sock "
Os bancos de dados SQLite são armazenados no sistema de arquivos, portanto você não precisa especificar um host. Por padrão, os arquivos são relativos ao diretório atual. Por exemplo, o seguinte criará um banco de dados em ./db/database.sqlite3
:
DATABASE_URL= " sqlite:db/database.sqlite3 "
Para especificar um caminho absoluto, adicione uma barra ao caminho. O seguinte criará um banco de dados em /tmp/database.sqlite3
:
DATABASE_URL= " sqlite:/tmp/database.sqlite3 "
DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name "
Para trabalhar com cluster ClickHouse, existem 4 parâmetros de consulta de conexão que podem ser fornecidos:
on_cluster
- Indicação para usar instruções de cluster e tabela de migração replicada. (padrão: false
) Se esse parâmetro não for fornecido, outros parâmetros de consulta relacionados ao cluster serão ignorados. 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
(Opcional) - Valor da macro a ser usado para instruções ON CLUSTER e para o caminho do zookeeper do mecanismo de tabela de migração replicado. (padrão: {cluster}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&cluster_macro={my_cluster} "
replica_macro
(Opcional) – Valor da macro a ser usado para o nome da réplica no mecanismo da tabela de migração replicada. (padrão: {replica}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&replica_macro={my_replica} "
zoo_path
(Opcional) - O caminho para a migração da tabela no ClickHouse/Zoo Keeper. (padrão: /clickhouse/tables/<cluster_macro>/{table}
) DATABASE_URL= " clickhouse://username:[email protected]:9000/database_name?on_cluster&zoo_path=/zk/path/tables "
Veja outras opções de conexão suportadas.
Siga o seguinte formato para DATABASE_URL
ao conectar-se ao BigQuery real no GCP:
bigquery://projectid/location/dataset
projectid
(obrigatório) - ID do projeto
dataset
(obrigatório) - Nome do conjunto de dados dentro do Projeto
location
(opcional) - Onde o conjunto de dados é criado
NOTA: Siga este documento sobre como definir a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS
para autenticação adequada
Siga o seguinte formato se estiver tentando se conectar a um endpoint personalizado, por exemplo, BigQuery Emulator
bigquery://host:port/projectid/location/dataset?disable_auth=true
disable_auth
(opcional) - Passe true
para pular a autenticação, use apenas para testar e conectar ao emulador.
O suporte ao Spanner está atualmente limitado a bancos de dados que utilizam o dialeto PostgreSQL, que deve ser escolhido durante a criação do banco de dados. Para o futuro suporte do Spanner com GoogleSQL, consulte esta discussão.
O Spanner com a interface Postgres requer que o PGAdapter esteja em execução. Use o seguinte formato para DATABASE_URL
, com o host e a porta configurados para onde o PGAdapter está sendo executado:
DATABASE_URL= " spanner-postgres://127.0.0.1:5432/database_name?sslmode=disable "
Observe que não é necessário especificar um nome de usuário e senha, pois a autenticação é feita pelo PGAdapter (eles serão ignorados pelo PGAdapter se especificados).
Outras opções do driver postgres são suportadas.
O Spanner também não permite que DDL seja executado dentro de transações explícitas. Portanto, você deve especificar transaction:false
em migrações que incluem DDL:
-- migrate:up transaction:false
CREATE TABLE ...
-- migrate:down transaction:false
DROP TABLE ...
Atualmente, os dumps de esquema não são suportados, pois pg_dump
usa funções que não são fornecidas pelo Spanner.
Para criar uma nova migração, execute dbmate new create_users_table
. Você pode nomear a migração como quiser. Isso criará um arquivo db/migrations/20151127184807_create_users_table.sql
no diretório atual:
-- migrate:up
-- migrate:down
Para escrever uma migração, basta adicionar seu SQL à seção migrate:up
:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
email varchar ( 255 ) not null
);
-- migrate:down
Nota: Os arquivos de migração são nomeados no formato
[version]_[description].sql
. Somente a versão (definida como todos os caracteres numéricos iniciais no nome do arquivo) é registrada no banco de dados, para que você possa renomear com segurança um arquivo de migração sem causar nenhum efeito no estado atual do aplicativo.
Execute dbmate up
para executar quaisquer migrações pendentes.
$ dbmate up
Creating: myapp_development
Applying: 20151127184807_create_users_table.sql
Applied: 20151127184807_create_users_table.sql in 123µs
Writing: ./db/schema.sql
Nota:
dbmate up
criará o banco de dados se ele ainda não existir (assumindo que o usuário atual tenha permissão para criar bancos de dados). Se você deseja executar migrações sem criar o banco de dados, executedbmate migrate
.
As migrações pendentes são sempre aplicadas em ordem numérica. No entanto, o dbmate não impede que as migrações sejam aplicadas fora de ordem se forem confirmadas de forma independente (por exemplo: se um desenvolvedor estiver trabalhando em uma ramificação há muito tempo e fizer o commit de uma migração que tenha um número de versão inferior ao de outras já- migrações aplicadas, o dbmate simplesmente aplicará a migração pendente). Consulte o nº 159 para uma explicação mais detalhada.
Por padrão, o dbmate não sabe como reverter uma migração. No desenvolvimento, muitas vezes é útil poder reverter seu banco de dados para um estado anterior. Para fazer isso, implemente a seção migrate:down
:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
email varchar ( 255 ) not null
);
-- migrate:down
drop table users;
Execute dbmate rollback
para reverter a migração mais recente:
$ dbmate rollback
Rolling back: 20151127184807_create_users_table.sql
Rolled back: 20151127184807_create_users_table.sql in 123µs
Writing: ./db/schema.sql
dbmate suporta opções passadas para um bloco de migração na forma de pares key:value
. Lista de opções suportadas:
transaction
transação
transaction
é útil se você não deseja executar SQL dentro de uma transação:
-- migrate:up transaction:false
ALTER TYPE colors ADD VALUE ' orange ' AFTER ' red ' ;
transaction
será padronizado como true
se seu banco de dados suportar.
Se você usar um ambiente de desenvolvimento Docker para seu projeto, poderá encontrar problemas com o banco de dados que não fica pronto imediatamente ao executar migrações ou testes de unidade. Isso pode ocorrer porque o servidor de banco de dados acabou de ser iniciado.
Em geral, seu aplicativo deve ser resistente a não ter uma conexão de banco de dados funcional na inicialização. No entanto, para fins de execução de migrações ou testes unitários, isso não é prático. O comando wait
evita essa situação permitindo pausar um script ou outro aplicativo até que o banco de dados esteja disponível. O Dbmate tentará uma conexão com o servidor de banco de dados a cada segundo, até um máximo de 60 segundos.
Se o banco de dados estiver disponível, wait
não retornará nenhuma saída:
$ dbmate wait
Se o banco de dados estiver indisponível, wait
bloqueará até que o banco de dados fique disponível:
$ dbmate wait
Waiting for database....
Você também pode usar o sinalizador --wait
com outros comandos se às vezes você observar falhas causadas pelo fato de o banco de dados ainda não estar pronto:
$ dbmate --wait up
Waiting for database....
Creating: myapp_development
Você pode personalizar o tempo limite usando --wait-timeout
(padrão 60s). Se o banco de dados ainda não estiver disponível, o comando retornará um erro:
$ dbmate --wait-timeout=5s wait
Waiting for database.....
Error: unable to connect to database: dial tcp 127.0.0.1:5432: connect: connection refused
Observe que o comando wait
não verifica se o banco de dados especificado existe, apenas se o servidor está disponível e pronto (portanto, ele retornará sucesso se o servidor de banco de dados estiver disponível, mas seu banco de dados ainda não tiver sido criado).
Quando você executa os comandos up
, migrate
ou rollback
, o dbmate criará automaticamente um arquivo ./db/schema.sql
contendo uma representação completa do esquema do seu banco de dados. O Dbmate mantém esse arquivo atualizado para você, portanto você não deve editá-lo manualmente.
Recomenda-se verificar esse arquivo no controle de origem, para que você possa revisar facilmente as alterações no esquema em confirmações ou solicitações pull. Também é possível usar esse arquivo quando você deseja carregar rapidamente um esquema de banco de dados, sem executar cada migração sequencialmente (por exemplo, em seu equipamento de teste). No entanto, se você não deseja salvar este arquivo, você pode adicioná-lo ao seu .gitignore
ou passar a opção de linha de comando --no-dump-schema
.
Para fazer dump do arquivo schema.sql
sem executar nenhuma outra ação, execute dbmate dump
. Ao contrário de outras ações dbmate, este comando depende dos respectivos comandos pg_dump
, mysqldump
ou sqlite3
disponíveis em seu PATH. Se essas ferramentas não estiverem disponíveis, o dbmate ignorará silenciosamente a etapa de despejo de esquema durante as ações up
, migrate
ou rollback
. Você pode diagnosticar o problema executando dbmate dump
e observando a saída:
$ dbmate dump
exec: " pg_dump " : executable file not found in $PATH
Em sistemas Ubuntu ou Debian, você pode corrigir isso instalando postgresql-client
, mysql-client
ou sqlite3
respectivamente. Certifique-se de que a versão do pacote instalada seja maior ou igual à versão em execução no servidor de banco de dados.
Nota: O arquivo
schema.sql
conterá um esquema completo para seu banco de dados, mesmo que algumas tabelas ou colunas tenham sido criadas fora das migrações do dbmate.
O Dbmate foi projetado para ser usado como CLI com qualquer linguagem ou estrutura, mas também pode ser usado como biblioteca em um aplicativo Go.
Aqui está um exemplo simples. Lembre-se de importar o driver que você precisa!
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 )
}
}
Consulte a documentação de referência para mais opções.
As migrações podem ser incorporadas ao binário do seu aplicativo usando a funcionalidade incorporada do Go.
Use db.FS
para especificar o sistema de arquivos usado para leitura de migrações:
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 )
}
}
Os arquivos de migração são muito simples e são armazenados em ./db/migrations
por padrão. Você pode criar um novo arquivo de migração chamado [date]_create_users.sql
executando dbmate new create_users
. Aqui está um exemplo:
-- migrate:up
create table users (
id integer ,
name varchar ( 255 ),
);
-- migrate:down
drop table if exists users;
As migrações ascendentes e descendentes são armazenadas no mesmo arquivo, para facilitar a edição. As diretivas up e down são necessárias, mesmo se você optar por não implementar a migração down.
Quando você aplica uma migração, o dbmate armazena apenas o número da versão, não o conteúdo, portanto você deve sempre reverter uma migração antes de modificar seu conteúdo. Por esse motivo, você pode renomear um arquivo de migração com segurança sem afetar seu status aplicado, desde que mantenha o número da versão intacto.
O arquivo de esquema é gravado em ./db/schema.sql
por padrão. É um despejo completo do esquema do seu banco de dados, incluindo quaisquer migrações aplicadas e quaisquer outras modificações que você tenha feito.
Esse arquivo deve ter check-in no controle de origem, para que você possa comparar facilmente a diferença de uma migração. Você pode usar o arquivo de esquema para restaurar rapidamente seu banco de dados sem precisar executar todas as migrações.
O Dbmate armazena um registro de cada migração aplicada na tabela chamada schema_migrations
. Esta tabela será criada automaticamente para você se ainda não existir.
A tabela é muito simples:
CREATE TABLE IF NOT EXISTS schema_migrations (
version VARCHAR ( 255 ) PRIMARY KEY
)
Você pode personalizar o nome desta tabela usando o sinalizador --migrations-table
ou a variável de ambiente DBMATE_MIGRATIONS_TABLE
.
Por que outra ferramenta de migração de esquema de banco de dados? O Dbmate foi inspirado em muitas outras ferramentas, principalmente Active Record Migrations, com o objetivo de ser fácil de configurar e independente de linguagem e estrutura. Aqui está uma comparação entre o dbmate e outras ferramentas de migração populares.
dbmate | ganso | migração sql | migração golang | registro ativo | sequelar | rota aérea | espertinho | |
---|---|---|---|---|---|---|---|---|
Características | ||||||||
Arquivos de migração SQL simples | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
Suporte para criação e eliminação de bancos de dados | ✅ | ✅ | ||||||
Suporte para salvar arquivos de despejo de esquema | ✅ | ✅ | ||||||
Arquivos de migração com versão de carimbo de data/hora | ✅ | ✅ | ✅ | ✅ | ✅ | |||
Tabela de migrações de esquema personalizado | ✅ | ✅ | ✅ | ✅ | ||||
Capacidade de esperar que o banco de dados fique pronto | ✅ | |||||||
String de conexão do banco de dados carregada de variáveis de ambiente | ✅ | ✅ | ||||||
Carregar automaticamente o arquivo .env | ✅ | |||||||
Nenhum arquivo de configuração separado | ✅ | ✅ | ✅ | ✅ | ✅ | |||
Independente de linguagem/estrutura | ✅ | ✅ | ✅ | ✅ | ✅ | |||
Motoristas | ||||||||
PostgreSQL | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
MySQL | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
SQLite | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ClickHouse | ✅ | ✅ | ✅ | ✅ |
Se você notar alguma imprecisão nesta tabela, proponha uma alteração.
Dbmate é escrito em Go, solicitações pull são bem-vindas.
Os testes são executados em um banco de dados real usando docker compose. Para construir uma imagem docker e executar os testes:
$ make docker-all
Para iniciar um shell de desenvolvimento:
$ make docker-sh