12 KiB
12 KiB
数据库迁移工具 - 完整指南
📌 核心特点
- ✅ 独立工具,零耦合 - 与应用代码完全分离
- ✅ 生产就绪 - 编译成二进制,无需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:环境变量(推荐生产环境)
# 使用 DATABASE_URL(最简单)
export DATABASE_URL="mysql://root:password@localhost:3306/mydb"
./bin/migrate up
# 覆盖配置路径
export CONFIG_FILE="/etc/app/config.json"
export MIGRATIONS_DIR="/opt/app/migrations"
./bin/migrate up
配置优先级(从高到低)
- 命令行参数
-config和-dir(最高) - 环境变量
CONFIG_FILE和MIGRATIONS_DIR - 环境变量
DATABASE_URL - 默认值
config.json和migrations
🐳 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:
DATABASE_URL: mysql://root:password@db:3306/mydb
command: sh -c "./migrate up && ./server"
# 注意:DATABASE_URL 的值应该指向你的数据库服务
# 例如:mysql://user:pass@your-db-host:3306/dbname
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: Run Migrations
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./bin/migrate up
- 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(容器内无法访问宿主机) - ✅
db(docker-compose 服务名) - ✅
host.docker.internal(Mac/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
DATABASE_URL="mysql://..." ./bin/migrate up
./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 的迁移工具,你可以:
- ✅ 复制一个模板文件到
cmd/migrate/main.go - ✅ 创建 SQL 迁移文件到
migrations/ - ✅ 编译:
go build -o bin/migrate cmd/migrate/main.go - ✅ 使用:
./bin/migrate up
核心优势:
- 独立工具,零耦合
- 生产就绪,无需Go环境
- 灵活配置,支持多环境
- Docker友好,修改配置无需重启
开箱即用,灵活强大! 🎉