Files
go-common/MIGRATION.md

581 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数据库迁移工具 - 完整指南
## 📌 核心特点
-**独立工具,零耦合** - 与应用代码完全分离
-**生产就绪** - 编译成二进制无需Go环境
-**灵活配置** - 支持命令行参数、环境变量、配置文件
-**Docker友好** - 挂载配置,修改无需重启容器
---
## 🚀 快速开始3步
> **黑盒模式**:迁移工具内部调用 `migration.RunMigrationsFromConfig()` 方法自动处理配置加载、数据库连接、迁移执行等所有细节。你只需要提供配置文件和SQL文件即可。
### 1. 复制迁移工具模板
```bash
mkdir -p cmd/migrate
cp /path/to/go-common/templates/migrate/main.go cmd/migrate/
```
### 2. 创建迁移文件
```bash
mkdir -p migrations
```
创建 `migrations/20240101000001_create_users.sql`
```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. 编译和使用
```bash
# 编译(生产环境推荐)
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 # 查看帮助
```
---
## 💻 本地使用
### 开发环境
```bash
# 直接运行需要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
```
### 命令说明
```bash
./bin/migrate -help
# 输出:
# 用法: migrate [命令] [选项]
#
# 命令:
# up 执行所有待执行的迁移(默认)
# down 回滚最后一个迁移
# status 查看迁移状态
#
# 选项:
# -config, -c 配置文件路径(默认: config.json
# -dir, -d 迁移文件目录(默认: migrations
# -help, -h 显示帮助信息
```
### 配置方式
#### 方式1配置文件推荐开发环境
`config.json`:
```json
{
"database": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"user": "root",
"password": "password",
"database": "mydb"
}
}
```
#### 方式2环境变量指定配置文件路径推荐生产环境
```bash
# 使用环境变量指定配置文件路径
export CONFIG_FILE="/etc/app/config.json"
export MIGRATIONS_DIR="/opt/app/migrations"
./bin/migrate up
```
#### 配置优先级(从高到低)
1. 命令行参数 `-config``-dir`(最高)
2. 环境变量 `CONFIG_FILE``MIGRATIONS_DIR`
3. 默认值 `config.json``migrations`
---
## 🐳 Docker 使用
### 方式1挂载配置文件推荐
**优势**:修改配置无需重启容器!
#### docker-compose.yml
```yaml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
volumes:
# 挂载配置文件(推荐:修改配置无需重启容器)
- ./config.json:/app/config.json:ro
# 启动时先执行迁移,再启动应用
command: sh -c "./migrate up && ./server"
```
#### 使用方式
```bash
# 1. 启动服务
docker-compose up -d
# 2. 修改配置文件
vim config.json
# 3. 手动执行迁移(无需重启容器!)
docker-compose exec app ./migrate up
# 4. 查看状态
docker-compose exec app ./migrate status
```
### 方式2指定配置文件路径
适用于多环境部署:
```yaml
services:
app:
build: .
volumes:
# 挂载不同环境的配置文件
- ./config.prod.json:/app/config.json:ro
command: sh -c "./migrate up -config /app/config.json && ./server"
```
```bash
# 手动切换环境(修改挂载的配置文件后)
docker-compose exec app ./migrate up
```
### 方式3使用环境变量指定配置文件路径
适用于多环境部署,通过环境变量指定不同环境的配置文件:
```yaml
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
```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 执行迁移
```yaml
# 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
```
### 部署流程
```bash
# 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
```yaml
# .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
```yaml
# .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`
### 创建迁移文件
```bash
# 获取时间戳
date +%Y%m%d%H%M%S
# 输出20240101120000
# 创建迁移文件
vim migrations/20240101120000_create_posts.sql
```
### 迁移文件示例
**Up 文件**
```sql
-- 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 文件**(可选):
```sql
-- migrations/20240101000001_create_users.down.sql
DROP INDEX idx_users_email ON users;
DROP TABLE IF EXISTS users;
```
### 兼容性建议
使用条件语句确保迁移可重复执行:
```sql
-- 创建表
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**: **编译成二进制文件**
```bash
# 本地或CI中编译
go build -o bin/migrate cmd/migrate/main.go
# 部署二进制文件不需要Go环境
scp bin/migrate server:/app/
ssh server "/app/migrate up"
```
### Q: Docker中修改配置需要重启吗
**A**: **不需要!** 使用挂载方式:
```yaml
volumes:
- ./config.json:/app/config.json:ro
```
修改后直接执行:
```bash
docker-compose exec app ./migrate up
```
### Q: 如何指定不同的配置文件?
**A**: 使用命令行参数:
```bash
# 开发环境
./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` 快速迭代
- 使用配置文件管理不同环境
```bash
go run cmd/migrate/main.go up -config config.dev.json
```
### 2. 测试环境
- 编译后部署,模拟生产环境
- 使用独立的数据库
```bash
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up -config config.test.json
```
### 3. 生产环境
- 编译后部署,先执行迁移再启动应用
- 使用配置文件管理敏感信息
```bash
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up -config config.json
./bin/server
```
### 4. Docker 部署
- 多阶段构建,只包含二进制文件
- 挂载配置文件,灵活修改
```dockerfile
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
- 在构建阶段编译
- 部署前执行迁移
```yaml
- 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
```
---
## 📚 更多资源
- [模板文件](./templates/) - 可直接复制的模板
- [完整文档](./docs/migration.md) - 详细功能文档
- [配置文档](./docs/config.md) - 配置说明
---
## 🎯 总结
使用 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友好修改配置无需重启
**开箱即用,灵活强大!** 🎉