Go Database Migration 與 ORM 規範:Migration 工具選擇(golang-migrate/goose)、 命名慣例、版本控制、CI/CD 整合、最佳實務(pt-online-schema-change, gh-ost)。 **適用場景**:設計資料庫遷移策略、實作 Migration、管理 Schema 版本、處理大型表變更、 配置 CI/CD Pipeline、避免 AutoMigrate、GORM 使用規範。
相關 Skills:本規範建議搭配
go-ddd(Repository Pattern)
原則:
gorm.AutoMigrate() 於生產環境(僅限本地開發)# golang-migrate
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
# goose
go install github.com/pressly/goose/v3/cmd/goose@latest
migrations/
├── 20260108120000_create_users_table.up.sql
├── 20260108120000_create_users_table.down.sql
├── 20260108130000_add_email_index.up.sql
├── 20260108130000_add_email_index.down.sql
├── 20260109100000_alter_orders_add_status.up.sql
└── 20260109100000_alter_orders_add_status.down.sql
格式:YYYYMMDDHHMMSS_<description>.<up|down>.sql
規則:
.up.sql 都有對應的 .down.sql範例:
# 正確
20260108120000_create_users_table.up.sql
20260108120000_create_users_table.down.sql
# 錯誤
2026-01-08-CreateUsers.sql # 格式錯誤
create_users.up.sql # 缺少時間戳
20260108120000_AddUserEmail.up.sql # 應使用 snake_case
20260108120000_create_users_table.up.sql:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
20260108120000_create_users_table.down.sql:
DROP INDEX IF EXISTS idx_users_email;
DROP TABLE IF EXISTS users;
20260109100000_alter_orders_add_status.up.sql:
-- 新增欄位(帶預設值避免 NULL 問題)
ALTER TABLE orders
ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'pending';
-- 新增索引
CREATE INDEX idx_orders_status ON orders(status);
20260109100000_alter_orders_add_status.down.sql:
DROP INDEX IF EXISTS idx_orders_status;
ALTER TABLE orders
DROP COLUMN IF EXISTS status;
錯誤做法:
-- ❌ 修改已執行的 migration
-- 20260108120000_create_users_table.up.sql
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) NOT NULL,
-- 後來加上的欄位(不應修改已執行的 migration)
phone VARCHAR(20) NOT NULL
);
正確做法:
-- ✅ 新增一個新的 migration
-- 20260110150000_add_phone_to_users.up.sql
ALTER TABLE users
ADD COLUMN phone VARCHAR(20);
原則:
main() 中執行 migration(避免多副本競爭)# deployment.yaml
apiVersion: apps/v1