数据库迁移管理
概述
本目录采用版本化数据库迁移策略,确保数据库结构变更的可追溯性和可回滚性。
目录结构
migrations/
├── README.md # 本文档
├── V1.0.0__baseline.sql # 基线版本(初始完整数据库)
├── V2.0.0__add_features.sql # 2.0.0版本新增功能
├── V2.0.1__fix_indexes.sql # 2.0.1版本索引优化
├── V2.0.2__add_columns.sql # 2.0.2版本字段新增
├── V2.0.3__current.sql # 当前版本
└── rollback/ # 回滚脚本目录
├── R2.0.3__rollback.sql
└── ...
命名规范
迁移文件命名
格式:V{版本号}__{描述}.sql
- 版本号:语义化版本号,如 1.0.0, 2.0.3
- 描述:简短的英文描述,使用下划线分隔
- 示例:
V1.0.0__baseline.sql- 初始基线V2.0.0__add_health_features.sql- 添加健康特性V2.0.1__fix_user_indexes.sql- 修复用户索引V2.0.2__add_org_fields.sql- 添加组织字段
回滚文件命名
格式:R{版本号}__rollback.sql
- 版本号:对应迁移版本
- 示例:
R2.0.3__rollback.sql
迁移脚本编写规范
1. 文件头部信息
-- ============================================
-- 迁移版本: V2.0.3
-- 创建时间: 2025-11-28
-- 描述: 添加用户健康数据相关表和字段
-- 依赖版本: V2.0.2
-- ============================================
2. 幂等性原则
所有迁移脚本必须支持重复执行:
-- 正确示例 - 使用 IF NOT EXISTS
CREATE TABLE IF NOT EXISTS `t_new_table` (
`id` bigint NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 正确示例 - 检查字段是否存在
SET @col_exists = 0;
SELECT COUNT(*) INTO @col_exists
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 't_user'
AND column_name = 'new_field';
SET @sql = IF(@col_exists = 0,
'ALTER TABLE t_user ADD COLUMN new_field VARCHAR(100)',
'SELECT "Column already exists"');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 错误示例 - 不检查直接执行
ALTER TABLE t_user ADD COLUMN new_field VARCHAR(100); -- 重复执行会报错
3. 数据安全原则
-- 添加字段时提供默认值
ALTER TABLE t_user ADD COLUMN status TINYINT(1) DEFAULT 1 COMMENT '状态';
-- 修改字段类型前备份
CREATE TABLE IF NOT EXISTS t_user_backup_20251128 AS SELECT * FROM t_user;
-- 删除表前备份
RENAME TABLE t_old_table TO t_old_table_backup_20251128;
4. 事务控制
START TRANSACTION;
-- 迁移操作
CREATE TABLE IF NOT EXISTS ...
ALTER TABLE ...
-- 验证
SET @count = 0;
SELECT COUNT(*) INTO @count FROM t_new_table;
-- 如果验证失败可以回滚
-- ROLLBACK;
COMMIT;
迁移执行流程
方式1:Docker初始化(推荐用于新部署)
- 迁移脚本按版本号顺序放在
migrations/目录 - Docker启动时自动执行所有未应用的迁移
- 执行记录保存在
schema_migrations表
方式2:手动执行(用于已有数据库)
# 导出当前数据库作为基线
./db-migrate.sh export
# 应用特定版本迁移
./db-migrate.sh apply V2.0.3
# 应用所有待执行迁移
./db-migrate.sh apply-all
# 查看迁移状态
./db-migrate.sh status
# 回滚到指定版本
./db-migrate.sh rollback V2.0.2
迁移历史跟踪
系统自动创建 schema_migrations 表记录迁移历史:
CREATE TABLE IF NOT EXISTS `schema_migrations` (
`version` VARCHAR(50) NOT NULL PRIMARY KEY,
`description` VARCHAR(255),
`type` VARCHAR(20) DEFAULT 'migration',
`script` VARCHAR(255),
`checksum` VARCHAR(64),
`installed_by` VARCHAR(100),
`installed_on` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`execution_time` INT,
`success` BOOLEAN
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
版本发布流程
开发阶段
- 创建新的迁移文件:
V2.0.4__add_feature.sql - 本地测试迁移脚本
- 创建对应回滚脚本:
R2.0.4__rollback.sql - 测试回滚脚本
构建阶段
- 更新
.env中的版本号 - 构建新的 MySQL 镜像(包含最新迁移脚本)
- 测试镜像部署和迁移
生产部署
- 备份当前数据库
- 部署新镜像
- 自动应用迁移
- 验证迁移结果
- 如有问题执行回滚
最佳实践
- 小步迭代:每个迁移文件只包含少量相关变更
- 向后兼容:新版本应能兼容旧数据
- 测试优先:在测试环境充分测试后再生产部署
- 备份策略:每次迁移前自动备份
- 文档完整:迁移脚本包含详细注释
- 版本锁定:明确记录迁移依赖的版本
故障恢复
迁移失败
# 查看失败原因
./db-migrate.sh status
# 手动修复问题后重新应用
./db-migrate.sh apply V2.0.3 --force
# 或执行回滚
./db-migrate.sh rollback V2.0.2
数据恢复
# 从备份恢复
docker exec -i ljwx-mysql mysql -u root -p123456 test < backup_20251128.sql
# 重新应用迁移
./db-migrate.sh apply-all
示例
见 V1.0.0__baseline.sql 和 V2.0.3__current.sql 了解完整示例。