如何通过 Golang 使用迁移
来源:dev.to
时间:2024-12-19 15:37:14 254浏览 收藏
Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《如何通过 Golang 使用迁移》带大家来了解一下##content_title##,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力实战开发!
简单的示例应用程序展示如何使用 golang-migrate
为什么应该使用迁移?
很多人问这个问题,我试图列出这个列表来强调使用迁移的主要优点:
版本控制:主要也是最重要的之一是能够对数据库模式的不同修改进行版本控制。如果没有迁移,这些架构更改将是不连贯的并且无法跟踪,这将导致版本控制问题和可能的错误。
回滚:总是需要有一个回滚系统,以防出现任何故障。迁移系统始终有两种方法,向上应用数据库中的更改,向下负责快速一致地恢复更改:-)
自动化和 ci/cd 集成: 迁移可以自动化,使其成为 ci/cd 管道的一部分。这有助于顺利、一致地部署更改,无需手动干预。
我们可以找到更多优点,但我认为这些点很好地总结了主要优点。
如何在golang中实现迁移?
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 应用程序
创建一个简单的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() } }
当我们运行它时,我们有类似的输出:
迁移 cli
要运行 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
- ext:要生成的文件的扩展名。
- dir:将在其中创建迁移的目录。
- seq:迁移序列名称。
此命令将在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 表:
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
- 路径:迁移目录的路径。
- 数据库:定义数据库 dsn 连接。
注意:第一次运行迁移时,将创建一个表“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 使用迁移》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
-
505 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
125 收藏
-
110 收藏
-
369 收藏
-
132 收藏
-
308 收藏
-
157 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习