Files
SuperBizAgent-java/knowledge_base/infrastructure/flyway-best-practices.md
zhuyongxin 3956426c97 docs(knowledge): 添加测试知识库文档
新增 6 个知识库文档,用于测试 L0+L1 混合检索功能:

API 类:
- payment-errors.md - 支付网关错误码定义

领域知识类:
- spring-ai-tool-best-practices.md - Spring AI 工具定义最佳实践

基础设施类:
- redis-config.md - Redis 缓存配置指南
- mysql-connection-pool.md - MySQL 连接池配置
- flyway-best-practices.md - Flyway 数据库迁移最佳实践

故障排查类:
- fault-diagnosis-process.md - 故障诊断流程规范

所有文档均包含:
- 标准 frontmatter 元数据 (title, keywords, summary, category)
- 实用配置示例和代码片段
- 支持 L0 精确匹配的关键词
2026-06-24 16:19:10 +08:00

311 lines
6.5 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.
---
title: Flyway 数据库迁移最佳实践
keywords: [Flyway, 数据库迁移, 版本管理, schema, migration]
summary: Flyway 数据库迁移的命名规范、编写技巧、回滚策略和常见问题处理
category: infrastructure
---
# Flyway 数据库迁移最佳实践
## 命名规范
### 标准格式
```
V{version}__{description}.sql
示例:
V001__create_user_table.sql
V002__add_email_to_user.sql
V003__create_order_table.sql
V004__add_metadata_to_api_document.sql
```
**规则**:
- `V` 大写,表示 Versioned migration
- 版本号用 3 位数字(001, 002...)
- 两个下划线 `__` 分隔版本号和描述
- 描述用小写字母和下划线
### 版本号管理
```
V001 - 初始表结构
V002 - 添加字段
V003 - 创建索引
V004 - 修改字段类型
...
```
**建议**:
- 预留版本号空间(001, 010, 020...)
- 紧急修复用中间号(V005_hotfix__...)
## SQL 编写规范
### 添加列
```sql
-- ✅ 好的写法 - 包含默认值和注释
ALTER TABLE user
ADD COLUMN email VARCHAR(100) DEFAULT '' COMMENT '用户邮箱';
-- ❌ 不好的写法 - 缺少默认值
ALTER TABLE user
ADD COLUMN email VARCHAR(100); -- 已有数据会是 NULL
```
### 修改列
```sql
-- ✅ 先添加新列,再迁移数据,最后删除旧列
ALTER TABLE user ADD COLUMN new_status VARCHAR(20) DEFAULT 'active';
UPDATE user SET new_status = old_status WHERE old_status IS NOT NULL;
ALTER TABLE user DROP COLUMN old_status;
ALTER TABLE user CHANGE COLUMN new_status status VARCHAR(20);
-- ❌ 直接修改 - 可能导致数据丢失
ALTER TABLE user MODIFY COLUMN status INT;
```
### 创建索引
```sql
-- ✅ 指定索引名称
CREATE INDEX idx_user_email ON user(email);
CREATE INDEX idx_order_user_id ON `order`(user_id);
-- ❌ 不指定名称 - 自动生成的名称难以管理
CREATE INDEX ON user(email);
```
### 外键约束
```sql
-- ✅ 命名规范
ALTER TABLE `order`
ADD CONSTRAINT fk_order_user_id
FOREIGN KEY (user_id) REFERENCES user(id)
ON DELETE CASCADE;
-- ❌ 不指定名称
ALTER TABLE `order`
ADD FOREIGN KEY (user_id) REFERENCES user(id);
```
## 幂等性保证
### 检查表是否存在
```sql
-- 创建表前检查
CREATE TABLE IF NOT EXISTS user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
);
```
### 检查列是否存在
```sql
-- 添加列前检查
ALTER TABLE user
ADD COLUMN IF NOT EXISTS email VARCHAR(100);
-- 或使用存储过程(MySQL < 8.0)
SET @col_exists = (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_name = 'user' AND column_name = 'email'
);
SET @query = IF(@col_exists = 0,
'ALTER TABLE user ADD COLUMN email VARCHAR(100)',
'SELECT "Column exists" AS msg'
);
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
```
### 检查索引是否存在
```sql
CREATE INDEX IF NOT EXISTS idx_user_email ON user(email);
```
## 数据迁移
### 分批处理大表
```sql
-- ❌ 一次更新全部 - 可能锁表很久
UPDATE large_table SET status = 'active' WHERE status IS NULL;
-- ✅ 分批更新
UPDATE large_table
SET status = 'active'
WHERE status IS NULL
LIMIT 1000;
-- 重复执行直到影响行数为 0
```
### 使用事务(DDL 语句除外)
```sql
START TRANSACTION;
UPDATE user SET status = 'active' WHERE status = 'enabled';
UPDATE user SET status = 'inactive' WHERE status = 'disabled';
COMMIT;
```
## 回滚策略
### 不支持自动回滚
Flyway 社区版不支持自动回滚,需要手动编写撤销脚本:
```sql
-- V005__add_email_to_user.sql
ALTER TABLE user ADD COLUMN email VARCHAR(100);
-- V005__add_email_to_user.undo.sql (手动执行)
ALTER TABLE user DROP COLUMN email;
```
### 建议使用新版本修复
```sql
-- V005 出错了,不要回滚
-- 而是创建 V006 修复
-- V006__fix_user_email.sql
ALTER TABLE user MODIFY COLUMN email VARCHAR(200);
```
## 常见问题
### 问题 1: 迁移失败后状态卡住
**症状**:
```
FlywayException: Migration failed!
Schema history table shows failed migration.
```
**解决**:
```sql
-- 查看迁移历史
SELECT * FROM flyway_schema_history ORDER BY installed_rank DESC;
-- 删除失败记录
DELETE FROM flyway_schema_history WHERE version = '005' AND success = 0;
-- 修复 SQL 脚本后重新启动
```
### 问题 2: Checksum 不匹配
**症状**:
```
FlywayException: Checksum mismatch for migration version 005
```
**原因**:迁移脚本被修改了
**解决**:
```sql
-- 方案 1: 修复 checksum(仅开发环境)
UPDATE flyway_schema_history
SET checksum = NULL
WHERE version = '005';
-- 方案 2: 创建新版本(推荐)
-- 不要修改已执行的迁移脚本,创建 V006
```
### 问题 3: 多个开发者同时创建迁移
**场景**:
- 开发者 A 创建 V005
- 开发者 B 创建 V005
- 冲突!
**预防**:
```
使用时间戳版本号:
V20260624001__add_user_email.sql
V20260624002__add_order_index.sql
```
## 生产环境最佳实践
### 1. 先验证后应用
```bash
# 开发环境测试
mvn flyway:migrate
# 预生产环境验证
mvn flyway:migrate -Dflyway.url=jdbc:mysql://pre-prod-db:3306/db
# 生产环境应用
mvn flyway:migrate -Dflyway.url=jdbc:mysql://prod-db:3306/db
```
### 2. 备份数据库
```bash
# 应用迁移前备份
mysqldump -u root -p superbiz_agent > backup_before_v005.sql
# 应用迁移
mvn spring-boot:run
# 出问题时恢复
mysql -u root -p superbiz_agent < backup_before_v005.sql
```
### 3. 限制自动迁移
```yaml
# 生产环境配置
spring:
flyway:
enabled: false # 禁用自动迁移
# 手动触发
mvn flyway:migrate -Dspring.profiles.active=prod
```
### 4. 监控迁移时间
```sql
SELECT version, description, type, installed_on, execution_time
FROM flyway_schema_history
ORDER BY installed_rank DESC
LIMIT 10;
```
## 工具和命令
### Maven 命令
```bash
# 查看迁移信息
mvn flyway:info
# 执行迁移
mvn flyway:migrate
# 验证迁移
mvn flyway:validate
# 清空数据库(危险!仅开发环境)
mvn flyway:clean
```
### 配置文件
```yaml
spring:
flyway:
enabled: true
baseline-on-migrate: true # 已有数据库时从当前版本开始
locations: classpath:db/migration
table: flyway_schema_history
validate-on-migrate: true
```
## 团队协作规范
1. **迁移脚本不可修改**:已合并的脚本禁止修改
2. **版本号递增**:新脚本必须比最新版本号大
3. **命名规范统一**:遵循 `V{version}__{description}.sql`
4. **Code Review**:迁移脚本必须经过审查
5. **测试覆盖**:每个迁移都要测试(空库 + 有数据)