跳到主要内容

验证迁移安全性

支持仓库

本节描述的更改可在支持仓库的 PR #8 中找到。

验证迁移安全性

数据库是应用程序的核心组件,我们需要确保对它的更改不会破坏任何功能。规划不当的迁移可能导致数据丢失、应用停机等问题。Atlas 提供了一种机制来验证迁移是否可以安全运行,这种机制称为迁移检查(migration linting),本节将展示如何使用它来验证迁移的安全性。

检查迁移目录

要检查迁移目录,我们可以使用 atlas migrate lint 命令。为了演示这一点,假设我们需要将 User 模型中的 Title 字段从可选改为必填:

// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
field.String("email").
Unique(),
-- field.String("title").
-- Optional(),
++ field.String("title"),
}
}

重新运行代码生成:

go generate ./...

接下来,自动生成新的迁移:

atlas migrate diff user_title_required \
--dir "file://ent/migrate/migrations" \
--to "ent://ent/schema" \
--dev-url "docker://mysql/8/ent"

ent/migrate/migrations 目录中创建了一个新的迁移文件:

ent/migrate/migrations/20221116051710_user_title_required.sql
-- modify "users" table
ALTER TABLE `users` MODIFY COLUMN `title` varchar(255) NOT NULL;

现在,检查迁移目录:

atlas migrate lint --dev-url mysql://root:pass@localhost:3306/dev --dir file://ent/migrate/migrations --latest 1

Atlas 报告该迁移可能不安全:

20221116051710_user_title_required.sql: data dependent changes detected:

L2: Modifying nullable column "title" to non-nullable might fail in case it contains NULL values

Atlas 检测到此迁移不安全并阻止了运行。在这种情况下,Atlas 将此更改归类为数据依赖性更改,意味着更改可能会失败,具体取决于数据库中的实际数据。

Atlas 可以检测更多类型的问题,完整列表请参阅 Atlas 文档

在 CI 中检查迁移目录

在前一节中,我们了解了如何在本地检查迁移目录。本节将展示如何在 CI 中检查迁移目录,以确保在合并到主分支之前迁移历史记录是安全的。

GitHub Actions 是 GitHub 提供的一款流行的 CI/CD 产品。通过 GitHub Actions,用户可以轻松定义在 Git 仓库的各个生命周期事件中触发的工作流。例如,许多团队配置 GitHub Actions 在每次提交更改时运行所有单元测试。

GitHub Actions 的强大功能之一是其可扩展性:可以轻松将功能打包为模块(称为 "action"),供多个项目重复使用。

使用 GitHub 的团队如果希望确保所有数据库模式更改都是安全的,可以使用 atlas-action GitHub Action。

此操作使用 atlas migrate lint 命令检查迁移目录。该命令验证和分析迁移目录的内容,并对所选更改生成见解和诊断:

  • 确保迁移历史记录可以从任何时间点重放。
  • 当多个团队成员同时向迁移目录写入并发迁移时,防止意外的历史记录更改。
  • 检测是否进行了破坏性或不可逆的更改,或者更改是否依赖于表内容并可能导致迁移失败。

使用方法

在仓库中添加 .github/workflows/atlas-ci.yaml,内容如下:

name: Atlas CI
on:
# 每当 master 分支中的代码发生更改时运行,
# 请将其更改为你的根分支。
push:
branches:
- master
pull_request:
paths:
- 'ent/migrate/migrations/*'
jobs:
lint:
services:
# 启动一个 mysql:8.0.29 容器,用作分析的开发数据库。
mysql:
image: mysql:8.0.29
env:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: dev
ports:
- "3306:3306"
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.1
with:
fetch-depth: 0 # 除非下面设置了 "latest",否则是必需的。
- uses: ariga/atlas-action@v0
with:
dir: ent/migrate/migrations
dev-url: mysql://root:pass@localhost:3306/dev

现在,每当我们提交包含潜在不安全迁移的拉取请求时,Atlas GitHub Action 将运行并报告检查结果。例如,对于我们的数据依赖性更改:

如需更深入的文档,请参阅 Atlas 网站上的 atlas-action 文档。

让我们通过回填 title 列来修复此问题。在迁移文件中添加以下语句:

ent/migrate/migrations/20221116051710_user_title_required.sql
-- modify "users" table
UPDATE `users` SET `title` = "" WHERE `title` IS NULL;

ALTER TABLE `users` MODIFY COLUMN `title` varchar(255) NOT NULL;

重新计算迁移目录的哈希值:

atlas migrate hash --dir file://ent/migrate/migrations

重新运行 atlas migrate lint,可以看到迁移目录不再包含任何不安全的更改:

atlas migrate lint --dev-url mysql://root:pass@localhost:3306/dev --dir file://ent/migrate/migrations --latest 1

由于未发现问题,命令将以零退出码退出且无输出。

当我们将此更改提交到 GitHub 时,Atlas GitHub Action 将运行并报告问题已解决:

结论

在本节中,我们学习了如何使用 Atlas 在本地和 CI 中验证迁移的安全性。

至此,我们完成了关于如何将 Ent 项目从自动迁移升级到版本化迁移的教程。回顾一下,我们学习了如何:

  • 启用版本化迁移功能标志
  • 创建脚本以根据所需的 Ent 模式自动规划迁移
  • 使用 Atlas 将生产数据库升级为使用版本化迁移
  • 为项目规划自定义迁移
  • 使用 atlas migrate lint 安全验证迁移

下一步

更多 Ent 新闻和更新: