# 数据库迁移工具 - 完整指南 ## 📌 核心特点 - ✅ **独立工具,零耦合** - 与应用代码完全分离 - ✅ **生产就绪** - 编译成二进制,无需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友好,修改配置无需重启 **开箱即用,灵活强大!** 🎉