Automatic Migration Planning

Jeff Yen
8 min readAug 24, 2024

--

123

atlas migrate diff 命令簡化了編寫架構遷移的過程,通過自動生成所需的 SQL 腳本來將資料庫架構從當前狀態遷移到新的目標狀態。它的工作原理如下:

  1. 定義目標狀態: 開發者定義所需的架構狀態,可以通過 HCL 或 SQL 架構定義、資料庫 URL,或者使用外部 schemas(如 ORM)來完成。
  2. 比較當前狀態: Atlas 會將當前資料庫狀態與所定義的目標狀態進行比較,識別出它們之間的差異。
  3. 生成遷移腳本: 根據比較結果,Atlas 自動生成所需的 SQL 腳本,以將資料庫從當前狀態遷移到新的目標狀態。
  4. 維護遷移目錄: Atlas 管理一個遷移目錄,其中包含了從一個版本到下一個版本所需的 SQL 腳本。這些腳本明確指定了如何應用遷移變更。

這樣,atlas migrate diff 命令能夠幫助開發者快速和準確地生成遷移腳本,從而簡化資料庫架構遷移的過程。

Summary

要開始使用版本化遷移,執行 atlas migrate diff 命令。這個命令會生成一個新的遷移檔案,使遷移目錄與所定義的目標架構保持一致。

Generate migrations from HCL schemas

假設我們有一個包含單個表的 Atlas 架構,並且遷移目錄是空的:

schema "test" {}

table "users" {
schema = schema.test
column "id" {
type = int
}
}

我們來執行 atlas migrate diff 命令,並使用以下必要的參數來生成創建 users 表的遷移腳本:

  • --dir:遷移目錄的 URL,默認為 file://migrations
  • --to:目標狀態的 URL,可以是 HCL 或 SQL 架構定義,或者是資料庫 URL。
  • --dev-url:用於計算差異的開發資料庫的 URL。
  • --format(可選):用來格式化輸出的 Go 模板。
atlas migrate diff create_users \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://mysql/8/test"

預設情況下,遷移檔案的命名格式為 {{ now }}_{{ name }}.sql。如果你希望使用不同的檔案格式,可以在目錄 URL 中使用 format 查詢參數。

讓我們重複上述過程,這次更改 HCL 架構檔案並再次執行 Atlas 遷移編輯。我們在 HCL 架構中新增一個 name 欄位:

schema "test" {}

table "users" {
schema = schema.test
column "id" {
type = int
}
column "name" {
type = varchar(255)
}
}

然後再執行

atlas migrate diff add_users_name \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://mysql/8/dev"

你會注意到 Atlas 在遷移目錄中新增了一個檔案:20240824131023_add_users_name.sql

以下圖解說明了其工作原理。Atlas 會將遷移目錄應用到提供的開發資料庫上,載入當前狀態,然後將其與目標狀態進行比較,最後生成一個新的遷移腳本,用於從當前狀態遷移到目標狀態。

Generate migrations from SQL schemas

Atlas 允許你使用 SQL 架構來定義你的目標狀態。SQL 架構可以是包含 CREATEALTER 語句的單個檔案,或是包含多個 SQL 檔案的目錄。例如,假設我們有一個包含單個表的 SQL 架構,並且遷移目錄是空的:

CREATE TABLE `users` (
`id` int NOT NULL
)

讓我們執行 atlas migrate diff 命令,並使用以下必要的參數來生成創建 users 表的遷移腳本:

  • --dir:遷移目錄的 URL,默認為 file://migrations
  • --to:目標狀態的 URL,可以是 HCL 或 SQL 架構定義,或是資料庫 URL。
  • --dev-url:用於計算差異的開發資料庫的 URL。

讓我們重複上述過程,這次更改 SQL 架構檔案並再次執行 Atlas 遷移編輯。我們在 SQL 架構中新增一個 name 欄位:

CREATE TABLE `users` (
`id` int NOT NULL,
`name` varchar(255) NOT NULL
)

然後再執行

atlas migrate diff add_users_name \
--dir "file://migrations" \
--to "file://schema.sql" \
--dev-url "docker://mysql/8/dev"

你會注意到 Atlas 在遷移目錄中新增了一個檔案:

總結來說,上述範例說明了 Atlas 如何通過將遷移目錄應用到指定的開發資料庫來載入當前狀態,然後將其與 SQL 架構檔案中定義的目標狀態進行比較,並生成一個新的遷移腳本,從當前狀態遷移到目標狀態。

Generate migrations with custom qualifiers

在處理特定資料庫架構時,Atlas 生成的遷移腳本不包含架構限定詞,以便能夠多次在不同的架構上執行它們。然而,在某些情況下,可能需要這些限定詞。為了解決這個問題,Atlas 允許在 migrate diff 命令中使用 --qualifier 標誌來添加這些限定詞。

讓我們執行上述範例,這次加上 --qualifier 標誌,並比較輸出的結果:

atlas migrate diff create_users \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://mysql/8/dev" \
--qualifier "market"

執行 cat migrations/*.sql 將會打印出相同的遷移腳本,但這次 users 表會被限定在 market 架構下:

Generate migrations for the entire database

Atlas 支援為資料庫或多個架構生成遷移。在 PostgreSQL 中,可以使用 CREATE DATABASE 命令創建一個資料庫,並在其中包含多個架構。然而,在 MySQL 中,資料庫是一個實例,其中可以包含一個或多個架構。

假設我們有一個 Atlas 架構,該架構定義了兩個資料庫架構,每個架構中都包含一個表。

schema "auth" {}
schema "market" {}

table "users" {
schema = schema.market
column "name" {
type = int
}
}

table "tokens" {
schema = schema.auth
column "value" {
type = int
}
}

讓我們執行 atlas migrate diff 命令,來生成創建整個架構的遷移腳本。不過,與之前範例中 --dev-url 標誌設定為特定架構的 URL 不同,在這種情況下,我們需要在連接字串中省略架構名稱。

MySQL

atlas migrate diff create_all \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://mysql/8"

PostgreSQL

atlas migrate diff create_all \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://postgres/15"

如你所見,Atlas 生成了創建 authmarket 架構的語句,並將它們作為限定詞添加到創建的表中。

--

--