Files
go-common/MIGRATION.md

12 KiB
Raw Permalink Blame History

数据库迁移工具 - 完整指南

📌 核心特点

  • 独立工具,零耦合 - 与应用代码完全分离
  • 生产就绪 - 编译成二进制无需Go环境
  • 灵活配置 - 支持命令行参数、环境变量、配置文件
  • Docker友好 - 挂载配置,修改无需重启容器

🚀 快速开始3步

黑盒模式:迁移工具内部调用 migration.RunMigrationsFromConfig() 方法自动处理配置加载、数据库连接、迁移执行等所有细节。你只需要提供配置文件和SQL文件即可。

1. 复制迁移工具模板

mkdir -p cmd/migrate
cp /path/to/go-common/templates/migrate/main.go cmd/migrate/

2. 创建迁移文件

mkdir -p migrations

创建 migrations/20240101000001_create_users.sql

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

3. 编译和使用

# 编译(生产环境推荐)
go build -o bin/migrate cmd/migrate/main.go

# 使用
./bin/migrate up                               # 使用默认配置
./bin/migrate up -config /path/to/config.json  # 指定配置
./bin/migrate status                           # 查看状态
./bin/migrate -help                            # 查看帮助

💻 本地使用

开发环境

# 直接运行需要Go环境
go run cmd/migrate/main.go up
go run cmd/migrate/main.go up -config dev.json

# 编译后运行(推荐)
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up
./bin/migrate up -config config.prod.json
./bin/migrate up -c prod.json -d db/migrations

命令说明

./bin/migrate -help

# 输出:
# 用法: migrate [命令] [选项]
# 
# 命令:
#   up       执行所有待执行的迁移(默认)
#   down     回滚最后一个迁移
#   status   查看迁移状态
#
# 选项:
#   -config, -c   配置文件路径(默认: config.json
#   -dir, -d      迁移文件目录(默认: migrations
#   -help, -h     显示帮助信息

配置方式

方式1配置文件推荐开发环境

config.json:

{
    "database": {
        "type": "mysql",
        "host": "localhost",
        "port": 3306,
        "user": "root",
        "password": "password",
        "database": "mydb"
    }
}

方式2环境变量指定配置文件路径推荐生产环境

# 使用环境变量指定配置文件路径
export CONFIG_FILE="/etc/app/config.json"
export MIGRATIONS_DIR="/opt/app/migrations"
./bin/migrate up

配置优先级(从高到低)

  1. 命令行参数 -config-dir(最高)
  2. 环境变量 CONFIG_FILEMIGRATIONS_DIR
  3. 默认值 config.jsonmigrations

🐳 Docker 使用

方式1挂载配置文件推荐

优势:修改配置无需重启容器!

docker-compose.yml

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    volumes:
      # 挂载配置文件(推荐:修改配置无需重启容器)
      - ./config.json:/app/config.json:ro
    # 启动时先执行迁移,再启动应用
    command: sh -c "./migrate up && ./server"

使用方式

# 1. 启动服务
docker-compose up -d

# 2. 修改配置文件
vim config.json

# 3. 手动执行迁移(无需重启容器!)
docker-compose exec app ./migrate up

# 4. 查看状态
docker-compose exec app ./migrate status

方式2指定配置文件路径

适用于多环境部署:

services:
  app:
    build: .
    volumes:
      # 挂载不同环境的配置文件
      - ./config.prod.json:/app/config.json:ro
    command: sh -c "./migrate up -config /app/config.json && ./server"
# 手动切换环境(修改挂载的配置文件后)
docker-compose exec app ./migrate up

方式3使用环境变量指定配置文件路径

适用于多环境部署,通过环境变量指定不同环境的配置文件:

services:
  app:
    build: .
    environment:
      CONFIG_FILE: /app/config.prod.json
      MIGRATIONS_DIR: /app/migrations
    volumes:
      - ./config.prod.json:/app/config.prod.json:ro
    command: sh -c "./migrate up && ./server"

Dockerfile

FROM golang:1.21 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# 编译应用和迁移工具
RUN go build -o bin/server cmd/server/main.go
RUN go build -o bin/migrate cmd/migrate/main.go

FROM debian:bookworm-slim
WORKDIR /app
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

# 复制二进制文件和迁移文件
COPY --from=builder /app/bin/migrate .
COPY --from=builder /app/bin/server .
COPY --from=builder /app/migrations ./migrations

EXPOSE 8080

# 启动:先迁移,再启动应用
CMD ["sh", "-c", "./migrate up && ./server"]

# 注意:配置文件通过 volumes 挂载,不打包进镜像

☸️ Kubernetes 部署

使用 Job 执行迁移

# k8s-job-migrate.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: myapp:latest
        command: ["./migrate", "up", "-config", "/etc/config/database.json"]
        volumeMounts:
        - name: config
          mountPath: /etc/config
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: app-config
      restartPolicy: OnFailure

部署流程

# 1. 创建 ConfigMap
kubectl create configmap app-config --from-file=config.json

# 2. 执行迁移
kubectl apply -f k8s-job-migrate.yaml
kubectl wait --for=condition=complete job/db-migrate

# 3. 部署应用
kubectl apply -f k8s-deployment.yaml

🔧 CI/CD 集成

GitLab CI

# .gitlab-ci.yml
stages:
  - build
  - migrate
  - deploy

build:
  stage: build
  script:
    - go build -o bin/migrate cmd/migrate/main.go
    - go build -o bin/server cmd/server/main.go
  artifacts:
    paths:
      - bin/

migrate:
  stage: migrate
  script:
    - ./bin/migrate up -config config.prod.json
  environment:
    name: production

deploy:
  stage: deploy
  script:
    - ./bin/server

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Build
        run: |
          go build -o bin/migrate cmd/migrate/main.go
          go build -o bin/server cmd/server/main.go
      
      - name: Create Config File
        run: |
          echo '${{ secrets.CONFIG_JSON }}' > config.json
      
      - name: Run Migrations
        run: ./bin/migrate up -config config.json
      
      - name: Deploy
        run: ./bin/server

📁 迁移文件管理

文件命名规则

migrations/
├── 20240101000001_create_users.sql        # Up 迁移
├── 20240101000001_create_users.down.sql   # Down 回滚(可选)
├── 20240102000001_add_posts.sql
└── 20240102000001_add_posts.down.sql

格式:{时间戳}_{描述}.sql

创建迁移文件

# 获取时间戳
date +%Y%m%d%H%M%S
# 输出20240101120000

# 创建迁移文件
vim migrations/20240101120000_create_posts.sql

迁移文件示例

Up 文件

-- migrations/20240101000001_create_users.sql
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);

Down 文件(可选):

-- migrations/20240101000001_create_users.down.sql
DROP INDEX idx_users_email ON users;
DROP TABLE IF EXISTS users;

兼容性建议

使用条件语句确保迁移可重复执行:

-- 创建表
CREATE TABLE IF NOT EXISTS users (...);

-- 添加列
ALTER TABLE posts ADD COLUMN IF NOT EXISTS author_id BIGINT;

-- 创建索引
CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(author_id);

🔍 常见问题

Q: 为什么不直接在应用代码中调用?

A: 耦合度太高! 独立工具的优势:

  • 应用和迁移完全解耦
  • 可以独立部署和执行
  • 更灵活的部署策略
  • 符合单一职责原则

Q: 生产环境没有Go怎么办

A: 编译成二进制文件

# 本地或CI中编译
go build -o bin/migrate cmd/migrate/main.go

# 部署二进制文件不需要Go环境
scp bin/migrate server:/app/
ssh server "/app/migrate up"

Q: Docker中修改配置需要重启吗

A: 不需要! 使用挂载方式:

volumes:
  - ./config.json:/app/config.json:ro

修改后直接执行:

docker-compose exec app ./migrate up

Q: 如何指定不同的配置文件?

A: 使用命令行参数:

# 开发环境
./migrate up -config config.dev.json

# 测试环境
./migrate up -config config.test.json

# 生产环境
./migrate up -config /etc/app/config.prod.json

Q: 多个实例同时启动会有问题吗?

A: 不会。数据库会保证只有一个实例能执行迁移(通过版本号主键)。

Q: Docker连不上数据库

A: 注意主机名:

  • localhost(容器内无法访问宿主机)
  • dbdocker-compose 服务名)
  • host.docker.internalMac/Windows 访问宿主机)

💡 最佳实践

1. 开发环境

  • 使用 go run 快速迭代
  • 使用配置文件管理不同环境
go run cmd/migrate/main.go up -config config.dev.json

2. 测试环境

  • 编译后部署,模拟生产环境
  • 使用独立的数据库
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up -config config.test.json

3. 生产环境

  • 编译后部署,先执行迁移再启动应用
  • 使用配置文件管理敏感信息
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up -config config.json
./bin/server

4. Docker 部署

  • 多阶段构建,只包含二进制文件
  • 挂载配置文件,灵活修改
FROM golang:1.21 as builder
RUN go build -o bin/migrate cmd/migrate/main.go

FROM debian:bookworm-slim
COPY --from=builder /app/bin/migrate .
CMD ["sh", "-c", "./migrate up && ./server"]

5. CI/CD

  • 在构建阶段编译
  • 部署前执行迁移
- build: go build -o bin/migrate cmd/migrate/main.go
- migrate: ./bin/migrate up
- deploy: ./bin/server

📊 推荐的项目结构

your-project/
├── cmd/
│   ├── migrate/
│   │   └── main.go          # 迁移工具(独立)
│   └── server/
│       └── main.go          # 应用主程序
├── migrations/              # 迁移SQL文件
│   ├── 20240101000001_create_users.sql
│   └── 20240101000001_create_users.down.sql
├── config.json              # 配置文件
├── Dockerfile
├── docker-compose.yml
├── Makefile                 # 常用命令
└── go.mod

📚 更多资源


🎯 总结

使用 GoCommon 的迁移工具,你可以:

  1. 复制一个模板文件到 cmd/migrate/main.go
  2. 创建 SQL 迁移文件到 migrations/
  3. 编译:go build -o bin/migrate cmd/migrate/main.go
  4. 使用:./bin/migrate up

核心优势

  • 独立工具,零耦合
  • 生产就绪无需Go环境
  • 灵活配置,支持多环境
  • Docker友好修改配置无需重启

开箱即用,灵活强大! 🎉