新增 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 精确匹配的关键词
311 lines
6.5 KiB
Markdown
311 lines
6.5 KiB
Markdown
---
|
||
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. **测试覆盖**:每个迁移都要测试(空库 + 有数据)
|