0

0

如何通过 Golang 使用迁移

聖光之護

聖光之護

发布时间:2024-11-07 13:42:01

|

1020人浏览过

|

来源于dev.to

转载

简单的示例应用程序展示如何使用 golang-migrate

为什么应该使用迁移?

很多人问这个问题,我试图列出这个列表来强调使用迁移的主要优点:

版本控制:主要也是最重要的之一是能够对数据库模式的不同修改进行版本控制。如果没有迁移,这些架构更改将是不连贯的并且无法跟踪,这将导致版本控制问题和可能的错误。

回滚:总是需要有一个回滚系统,以防出现任何故障。迁移系统始终有两种方法,向上应用数据库中的更改,向下负责快速一致地恢复更改:-)

自动化和 ci/cd 集成: 迁移可以自动化,使其成为 ci/cd 管道的一部分。这有助于顺利、一致地部署更改,无需手动干预。

立即学习go语言免费学习笔记(深入)”;

我们可以找到更多优点,但我认为这些点很好地总结了主要优点。

如何在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()
 }
}

当我们运行它时,我们有类似的输出:

如何通过 Golang 使用迁移

迁移 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 表:

JTBC网站内容管理系统5.0.3.1
JTBC网站内容管理系统5.0.3.1

JTBC CMS(5.0) 是一款基于PHP和MySQL的内容管理系统原生全栈开发框架,开源协议为AGPLv3,没有任何附加条款。系统可以通过命令行一键安装,源码方面不基于任何第三方框架,不使用任何脚手架,仅依赖一些常见的第三方类库如图表组件等,您只需要了解最基本的前端知识就能很敏捷的进行二次开发,同时我们对于常见的前端功能做了Web Component方式的封装,即便是您仅了解HTML/CSS也

下载
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 应用程序来显示结果:

如何通过 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 应用程序运行它时,您可以看到新字段:

如何通过 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将应用于所有迁移

然后我们可以显示上次迁移已恢复并且电话字段已被删除:-)

display table users without phone field

如何解决迁移错误

如果迁移包含错误并被执行,则无法应用该迁移,并且迁移系统将阻止数据库上的任何进一步迁移,直到此迁移得到修复。

当尝试申请时,我们会收到如下消息:

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

182

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

229

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

343

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

396

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

240

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

194

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

478

2025.06.17

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

8

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 2万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 816人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号