使用 Golang 迁移

2025-06-10

使用 Golang 迁移

什么是迁移?

迁移被广泛用于维护数据库结构的版本控制,它是保持数据库井然有序的一个非常有用的解决方案。

假设您有一个用户表,并且需要在该表中插入一个新字段,如果没有迁移,您将需要手动运行 SQL,例如:

  ALTER TABLE "users" ADD COLUMN "phone" VARCHAR(255) NULL;
Enter fullscreen mode Exit fullscreen mode

现在,每次您需要重新创建users表时,您都需要记住创建此字段,除非您更改users表的原始创建,但随着表和应用程序的增长,这变得不可行,因此使用迁移是一个很好的选择。

迁徙

迁移的工作方式相对简单,我们通常有一个up文件和另一个down文件,一些 ORM(如PrismaORM)只创建 1 个文件,在该up文件中我们创建将创建或更改数据库的 SQL,在该down文件中我们创建撤消更改的 SQL。

有什么好处?

现在有了这些文件,我们维护了数据库更改的历史记录,每个更改都有其up文件down,现在如果我们需要创建表,我们运行所有up文件,一切都会创建,如果需要恢复,只需运行down

Go 中的迁移

Go 本身不支持使用迁移,但我们可以使用具有此功能的 ORM,例如社区最常用的 GORM,但我们可以在不使用 ORM 的情况下使用迁移,为此我们将使用golang -migrate包。

Golang 迁移包

golang-migrate是最适合此用途的,我们已经拥有管理迁移所需的一切,并且它几乎支持所有数据库,因此在我们的示例中我们将使用 PostgreSQL。

示例项目

我之前创建了一个简单的项目,但我会快速解释它,因为重点是使用迁移。

项目结构

我们将有这个结构,非常简单,示例的代码应该在main.go

  package main

  import (
    "database/sql"
    "fmt"
    "log"
    "os"

    "github.com/joho/godotenv"
    _ "github.com/lib/pq"
  )

  func main() {
    // load .env file
    godotenv.Load()

    postgresURI := os.Getenv("DATABASE_URL")
    db, err := sql.Open("postgres", postgresURI)
    if err != nil {
      log.Panic(err)
    }
    err = db.Ping()
    if err != nil {
      db.Close()
      log.Panic(err)
    }

    fmt.Println("Connected to database")

    // keep the program running
    select {}
  }
Enter fullscreen mode Exit fullscreen mode

使用 golang-migrate

我们需要安装 golang-migrate 包的 CLI,查看如何安装这里,运行命令:

  migrate -version
Enter fullscreen mode Exit fullscreen mode

如果输出类似于:

  v4.16.2
Enter fullscreen mode Exit fullscreen mode

好的,继续!下一步是使用以下命令创建我们的第一个迁移:

  migrate create -ext=sql -dir=internal/database/migrations -seq init
Enter fullscreen mode Exit fullscreen mode
  • ext:定义扩展,我们使用sql。
  • dir:这是我们将创建迁移的目录。
  • seq:定义迁移文件名的序列,我们将使用数字,也可以使用时间戳。

这样,您会注意到在数据库文件夹内创建了一个名为migrations的文件夹。

项目迁移

文件updown文件按顺序创建,因为第一个是000001,如果再次运行该migrate create命令,它将创建迁移000002。现在让我们创建 SQL 并运行迁移:

在该up文件中,我们将创建下表:

  CREATE TABLE users (
    id VARCHAR(36) NOT NULL PRIMARY KEY,
    first_name VARCHAR(255) NOT NULL,
    last_name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP(3) NOT NULL
  );
Enter fullscreen mode Exit fullscreen mode

现在down我们将在文件中删除表格:

  DROP TABLE IF EXISTS users;
Enter fullscreen mode Exit fullscreen mode

准备好 SQL 后,我们就可以运行up迁移了,不要忘记确保数据库正在运行,为此我在项目中留下了一个 docker compose 文件来运行 PostgreSQL 镜像。

  migrate -path=internal/database/migrations -database "postgresql://golang_migrate:golang_migrate@localhost:5432/golang_migrate?sslmode=disable" -verbose up
Enter fullscreen mode Exit fullscreen mode
  • path:定义我们的迁移位置。
  • database:数据库连接url。
  • -verbose:仅显示所有运行。

如果我们访问PgAdminBeekeeper之类的客户端,或者通过 bash 访问其容器并通过 CLI 检查,我们可以看到该表已成功创建:

养蜂人

现在我们可以运行了down,它是完全相同的命令,但是从 更改updown

  migrate -path=internal/database/migrations -database "postgresql://golang_migrate:golang_migrate@localhost:5432/golang_migrate?sslmode=disable" -verbose down
Enter fullscreen mode Exit fullscreen mode

这样,表格就被删除了。

添加更多字段

现在让我们看看如果需要向表中添加另一个字段会是什么样子users,如果没有迁移,我们就必须直接更改原始表,但是有了迁移,我们就不需要了,让我们创建另一个迁移:

  migrate create -ext=sql -dir=internal/database/migrations -seq init
Enter fullscreen mode Exit fullscreen mode

它将创建顺序为000002up的迁移,让我们添加字段:downphone

up

  ALTER TABLE "users" ADD COLUMN "phone" VARCHAR(255) NULL;
Enter fullscreen mode Exit fullscreen mode

down

  ALTER TABLE "users" DROP COLUMN "phone";
Enter fullscreen mode Exit fullscreen mode

再次运行时:

  migrate -path=internal/database/migrations -database "postgresql://golang_migrate:golang_migrate@localhost:5432/golang_migrate?sslmode=disable" -verbose up
Enter fullscreen mode Exit fullscreen mode

我们的phone字段已添加到用户表中,但是如果我只想down在添加该字段的迁移中添加它,该怎么办phone?可以,只需使用相同的命令,传递值 1,这意味着您要撤消上一次迁移:

  migrate -path=internal/database/migrations -database "postgresql://golang_migrate:golang_migrate@localhost:5432/golang_migrate?sslmode=disable" -verbose down 1
Enter fullscreen mode Exit fullscreen mode

phone字段已被删除。

让 CLI 更易于使用

如您所见,golang-migrate 命令使用起来可能有点累,我们可以通过使用文件makefile使其更容易。

  include .env

  create_migration:
    migrate create -ext=sql -dir=internal/database/migrations -seq init

  migrate_up:
    migrate -path=internal/database/migrations -database "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" -verbose up

  migrate_down:
    migrate -path=internal/database/migrations -database "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" -verbose down

  .PHONY: create_migration migrate_up migrate_down
Enter fullscreen mode Exit fullscreen mode

我们创建运行migrate命令的快捷方式,我们需要使用包含我们的环境include .env,然后我们创建命令:

  • create_migration:创建我们的迁移文件。
  • migrate_up:运行迁移up
  • migrate_down:运行迁移down
  • PHONY:它将执行一个命令,makefile 可能会尝试获取一个文件,migrate_up例如,如果存在具有该名称的文件。

有了它,只需使用以下命令:

  make create_migration
Enter fullscreen mode Exit fullscreen mode

我们将创建迁移文件,这适用于创建的其他快捷方式。

最后的考虑

在本文中,我们了解了如何使用迁移,以及它对于维护变更历史记录和方便数据库维护的重要性。但值得一提的是,错误地使用迁移可能会导致数据库中的数据丢失,因此了解迁移的工作原理以及 ORM 或编程语言如何处理迁移非常重要。

避免删除迁移,如果使用不当,它们可能会成为一场噩梦。

存储库链接

存储库项目

请参阅我博客上的这篇文章

Gopher 积分

鏂囩珷鏉ユ簮锛�https://dev.to/wiliamvj/using-migrations-with-golang-3449
PREV
什么是速率限制器以及为什么要使用它?
NEXT
React Three Fiber 和 NextJS 入门模板 使用模板 模板内容是什么? 入门指南 功能解析 变化 下一步是什么? 你能做什么?