简单的示例应用程序展示如何使用 golang-migrate
很多人问这个问题,我试图列出这个列表来强调使用迁移的主要优点:
版本控制:主要也是最重要的之一是能够对数据库模式的不同修改进行版本控制。如果没有迁移,这些架构更改将是不连贯的并且无法跟踪,这将导致版本控制问题和可能的错误。
回滚:总是需要有一个回滚系统,以防出现任何故障。迁移系统始终有两种方法,向上应用数据库中的更改,向下负责快速一致地恢复更改:-)
自动化和 ci/cd 集成: 迁移可以自动化,使其成为 ci/cd 管道的一部分。这有助于顺利、一致地部署更改,无需手动干预。
立即学习“go语言免费学习笔记(深入)”;
我们可以找到更多优点,但我认为这些点很好地总结了主要优点。
go 本身不支持该功能的迁移,因此我们可以使用流行的 golang-migrate 包,如果您使用像 gorm 这样的 orm,您也可以使用它。
这两个包都很受欢迎,但在这个例子中我将使用 golang-migrate,因为我对实现 orm 不感兴趣。
让我们一步步实现一个简单的应用程序,看看它是如何使用的。
要阅读本文,您需要:go 和 docker 以及 docker compose
在根目录中创建文件 docker-compose.yml,我们将在其中定义您最喜欢的数据库,在我的例子中使用 mariadb,但也可以随意使用另一个数据库。
services:
mariadb:
image: mariadb:11.5.2
container_name: mariadb_example_go_migration
ports:
- "3306:3306"
environment:
- mysql_database=app
- mysql_root_password=root
- tz=europe/berlin
volumes:
- mariadbdata:/var/lib/mysql
volumes:
mariadbdata:
driver: local
docker compose up -d
如果您愿意,可以直接使用 docker 而不是 docker-compose:
docker volume create -d local mariadbdata docker run --name mariadb_example_go_migration -p 3306:3306 -e mysql_database=app -e mysql_root_password=root -e tz=europe/berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
在根目录中创建或更新文件 .env,您需要在其中定义变量以连接我们的数据库。
database_dsn=root:root@tcp(localhost:3306)/app
创建一个简单的golang应用程序以确保成功的数据库连接并列出数据库中的所有表和结构及其结构。 cmd/main.go
package main
import (
"database/sql"
"fmt"
"log"
"os"
"text/tabwriter"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
func main() {
// load .env variables
err := godotenv.load()
if err != nil {
log.fatal("error loading .env file")
}
// open connection with mysql db
db, err := sql.open("mysql", os.getenv("database_dsn"))
if err != nil {
log.fatalf("error opening database: %v\n", err)
}
defer db.close()
// ensure that the connection works
err = db.ping()
if err != nil {
log.fatalf("error connecting database: %v\n", err)
}
fmt.println("connected to database")
// execute the show tables query to list all tables in the database
tables, err := db.query("show tables")
if err != nil {
log.fatalf("failed to execute show tables query: %v\n", err)
}
defer tables.close()
fmt.println("database structure:")
for tables.next() {
var tablename string
if err := tables.scan(&tablename); err != nil {
log.fatalf("failed to scan table name: %v\n", err)
}
w := tabwriter.newwriter(os.stdout, 0, 0, 2, ' ', tabwriter.debug)
fmt.printf("\n[table: %s]\n\n", tablename)
fmt.fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "field", "type", "null", "key", "default", "extra")
// get the structure of the current table
structurequery := fmt.sprintf("describe %s", tablename)
columns, err := db.query(structurequery)
if err != nil {
log.fatalf("failed to describe table %s: %v\n", tablename, err)
}
defer columns.close()
for columns.next() {
var field, coltype, null, key, defaultval, extra sql.nullstring
err := columns.scan(&field, &coltype, &null, &key, &defaultval, &extra)
if err != nil {
log.fatalf("failed to scan column: %v\n", err)
}
fmt.fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n",
field.string, coltype.string, null.string, key.string, defaultval.string, extra.string)
}
w.flush()
}
}
当我们运行它时,我们有类似的输出:

要运行 golang-migrate cli 基本上有两种方法在本地安装 cli 或通过官方 docker 镜像运行:migrate/migrate。
就我个人而言,我更喜欢 de docker 变体,但在本教程中说明了这两种变体。
第一步是使用下一个命令创建一个空迁移。
#cli variant migrate create -ext sql -dir ./database/migrations -seq create_users_table
#docker cli variant
docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \
create -ext sql -dir /migrations -seq create_users_table
此命令将在database/migrations/文件夹中生成两个空文件:000001createuserstable.up.sql和000001createuserstable.down.sql
在 000001createuserstable.up.sql 文件中定义创建表 users 的 sql:
create table `users` (
`id` varchar(36) not null primary key,
`name` varchar(255) not null,
`email` varchar(255) not null unique,
`password` varchar(255) not null
);
在 000001createuserstable.down.sql 文件中定义 sql 来恢复 up 所做的所有更改,在这种情况下我们必须删除 users 表:
PHP是一种功能强大的网络程序设计语言,而且易学易用,移植性和可扩展性也都非常优秀,本书将为读者详细介绍PHP编程。 全书分为预备篇、开始篇和加速篇三大部分,共9章。预备篇主要介绍一些学习PHP语言的预备知识以及PHP运行平台的架设;开始篇则较为详细地向读者介绍PKP语言的基本语法和常用函数,以及用PHP如何对MySQL数据库进行操作;加速篇则通过对典型实例的介绍来使读者全面掌握PHP。 本书
472
drop table if exists `users`;
以下命令应用所有待处理的迁移。您还可以通过在 up 后添加数字来定义要应用的迁移数量。
#cli variant migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
#docker cli variant
docker run --rm -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
注意:第一次运行迁移时,将创建一个表“schema_migrations”,其中迁移知道所应用的版本号。
并运行我们的 golang 应用程序来显示结果:

在用户表上添加新的电话列
#cli variant
migrate create -ext sql -dir ./database/migrations -seq add_column_phone
#docker cli variant
docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \
create -ext sql -dir /migrations -seq add_column_phone
-- 000002_add_column_phone.up.sql alter table `users` add `phone` varchar(255) null;
-- 000002_add_column_phone.down.sql alter table `users` drop `phone`;
#cli variant
migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
#docker cli variant
docker run --rm -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
当您从我们的 golang 应用程序运行它时,您可以看到新字段:

通过以下命令我们可以轻松回滚已应用的。迁徙。在下面的示例中,我们可以看到如何反转上次应用的迁移:
#cli variant migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" down 1
#docker cli variant
docker run --rm -it -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" down 1
警告:如果您没有定义迁移数量,rollback将应用于所有迁移!
然后我们可以显示上次迁移已恢复并且电话字段已被删除:-)

如果迁移包含错误并被执行,则无法应用该迁移,并且迁移系统将阻止数据库上的任何进一步迁移,直到此迁移得到修复。
当尝试申请时,我们会收到如下消息:
error: dirty database version 2. fix and force version.
不要惊慌,恢复一致的系统并不难。
首先,我们必须解决损坏的迁移问题,在本例中为版本 2。
迁移解决后,我们必须强制系统使用最新的有效版本,在本例中为版本 1。
#cli variant migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" force 1
#docker cli variant
docker run --rm -it -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" force 1
现在您可以毫无问题地重新应用迁移;-)
为了提高我们的工作效率并方便使用这些命令,我们可以使用 makefile。下面您可以看到两个变体:本机客户端和 docker。
cli 变体
include .env
.phony: help create-migration migrate-up migrate-down migrate-force
help: ## show help
@echo "\n\033[1mavailable commands:\033[0m\n"
@@awk 'begin {fs = ":.*##";} /^[a-za-z_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(makefile_list)
create-migration: ## create an empty migration
@read -p "enter the sequence name: " seq; \
migrate create -ext sql -dir ./database/migrations -seq $${seq}
migrate-up: ## migration up
@migrate -path=./database/migrations -database "mysql://${database_dsn}" up
migrate-down: ## migration down
@read -p "number of migrations you want to rollback (default: 1): " num; num=$${num:-1}; \
migrate -path=./database/migrations -database "mysql://${database_dsn}" down $${num}
migrate-force: ## migration force version
@read -p "enter the version to force: " version; \
migrate -path=./database/migrations -database "mysql://${database_dsn}" force $${version}
docker cli 变体
include .env
.PHONY: help create-migration migrate-up migrate-down migrate-force
help: ## Show help
@echo "\n\033[1mAvailable commands:\033[0m\n"
@@awk 'BEGIN {FS = ":.*##";} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
create-migration: ## Create an empty migration
@read -p "Enter the sequence name: " SEQ; \
docker run --rm -v ./database/migrations:/migrations migrate/migrate \
create -ext sql -dir /migrations -seq $${SEQ}
migrate-up: ## Migration up
@docker run --rm -v ./database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://${DATABASE_DSN}" up
migrate-down: ## Migration down
@read -p "Number of migrations you want to rollback (default: 1): " NUM; NUM=$${NUM:-1}; \
docker run --rm -it -v ./database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://${DATABASE_DSN}" down $${NUM}
migrate-force: ## Migration force version
@read -p "Enter the version to force: " VERSION; \
docker run --rm -it -v ./database/migrations:/migrations --network host migrate/migrate \
-path=/migrations -database "mysql://${DATABASE_DSN}" force $${VERSION}
本教程的代码可以在公共场合找到:github - albertcolom/example-go-migration
原文发表于:albertcolom.com
以上就是如何通过 Golang 使用迁移的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号