# 数据库迁移指南

本项目使用 **Flyway** 进行数据库版本管理和自动迁移。

## 概述

Flyway 是一个数据库迁移工具，它能够：
- 自动追踪数据库版本
- 按顺序执行迁移脚本
- 确保团队成员的数据库结构一致
- 支持回滚和修复

## 工作原理

1. 应用启动时，Flyway 自动扫描 `src/main/resources/db/migration` 目录
2. 检查 `flyway_schema_history` 表，确定已执行的版本
3. 按版本号顺序执行未运行的迁移脚本
4. 记录执行结果到历史表

## 迁移脚本命名规范

```
V{版本号}__{描述}.sql
```

### 命名规则

| 规则 | 说明 | 示例 |
|------|------|------|
| 前缀 | 必须以 `V` 开头（大写） | V1, V2, V10 |
| 版本号 | 数字，支持小数点 | 1, 2, 2.1, 10 |
| 分隔符 | **两个下划线** | `__` |
| 描述 | 用下划线连接单词 | add_user_table |
| 后缀 | 必须是 `.sql` | .sql |

### 正确示例

```
V1__baseline.sql                    # 基线版本
V2__add_project_fields.sql          # 添加项目字段
V3__create_order_table.sql          # 创建订单表
V4__add_index_to_user.sql           # 添加用户索引
V4.1__fix_user_column_type.sql      # 修复用户列类型（小版本）
V10__major_refactor.sql             # 大版本重构
```

### 错误示例

```
v1__init.sql          # 错误：v 应该大写
V1_init.sql           # 错误：只有一个下划线
V1-init.sql           # 错误：使用了连字符
V1__init.SQL          # 错误：后缀应该小写
init.sql              # 错误：缺少版本前缀
```

## 如何添加新的迁移

### 步骤 1：确定版本号

查看当前最新版本：
```bash
ls src/main/resources/db/migration/
```

新版本号 = 最新版本号 + 1

### 步骤 2：创建迁移脚本

在 `src/main/resources/db/migration/` 目录创建新文件：

```sql
-- =====================================================
-- 迁移脚本: [描述]
-- 版本: V{版本号}
-- 描述: [详细说明]
-- 日期: YYYY-MM-DD
-- =====================================================

-- 你的 SQL 语句
ALTER TABLE xxx ADD COLUMN yyy VARCHAR(100);
```

### 步骤 3：测试迁移

本地启动应用，观察日志：
```
Flyway Community Edition 9.x.x
Successfully validated 3 migrations
Current version of schema: 2
Migrating schema to version 3 - create_order_table
Successfully applied 1 migration
```

### 步骤 4：提交代码

```bash
git add src/main/resources/db/migration/V3__xxx.sql
git commit -m "db: 添加xxx迁移脚本"
git push
```

## 最佳实践

### 1. 幂等性脚本

编写可重复执行的脚本，避免重复执行报错：

```sql
-- 添加列（如果不存在）
SET @exist := (SELECT COUNT(*) FROM information_schema.columns 
               WHERE table_schema = DATABASE() 
               AND table_name = 'your_table' 
               AND column_name = 'new_column');
SET @sql := IF(@exist = 0, 
    'ALTER TABLE your_table ADD COLUMN new_column VARCHAR(100)',
    'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
```

### 2. 不要修改已执行的脚本

一旦迁移脚本被执行（已提交到版本库），**永远不要修改它**。

如果需要修复，创建新的迁移脚本：
```
V3__create_table.sql      # 已执行，有错误
V4__fix_v3_error.sql      # 新建脚本修复错误
```

### 3. 小步迁移

每个迁移脚本只做一件事：
- V2__add_user_email.sql
- V3__add_user_phone.sql
- 不要: V2__add_user_email_and_phone_and_address.sql

### 4. 添加注释

```sql
-- =====================================================
-- 迁移脚本: 添加用户邮箱字段
-- 版本: V5
-- 描述: 为用户表添加邮箱字段，用于接收通知
-- 作者: 张三
-- 日期: 2024-12-29
-- 关联需求: JIRA-123
-- =====================================================
```

### 5. 备份数据

生产环境执行迁移前，务必备份数据库：
```bash
mysqldump -u root -p martial_db > backup_$(date +%Y%m%d).sql
```

## 常见问题

### Q1: 迁移失败怎么办？

1. 查看错误日志，定位问题
2. 修复数据库中的问题（手动）
3. 修复迁移脚本
4. 执行 Flyway repair（如需要）

### Q2: 如何跳过某个版本？

不建议跳过版本。如果必须跳过，可以创建空脚本：
```sql
-- V3__placeholder.sql
-- 此版本跳过
SELECT 1;
```

### Q3: 多人开发版本冲突怎么办？

使用日期时间作为版本号前缀：
```
V20241229001__add_field.sql
V20241229002__fix_bug.sql
```

### Q4: 如何查看迁移历史？

```sql
SELECT * FROM flyway_schema_history ORDER BY installed_rank;
```

## 目录结构

```
src/main/resources/
└── db/
    └── migration/
        ├── V1__baseline.sql              # 基线版本
        ├── V2__add_project_fields.sql    # 添加项目字段
        └── V3__xxx.sql                   # 后续迁移...
```

## 配置说明

application.yml 中的 Flyway 配置：

```yaml
spring:
  flyway:
    enabled: true                          # 启用 Flyway
    locations: classpath:db/migration      # 迁移脚本位置
    table: flyway_schema_history           # 版本历史表名
    baseline-version: 0                    # 基线版本号
    baseline-on-migrate: true              # 自动执行基线
    validate-on-migrate: true              # 校验迁移脚本
    encoding: UTF-8                        # 脚本编码
    out-of-order: false                    # 禁止乱序执行
    clean-disabled: true                   # 禁用清理（生产安全）
```

## 参考资料

- [Flyway 官方文档](https://flywaydb.org/documentation/)
- [Spring Boot Flyway 集成](https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.migration-tool.flyway)
