Files
2025-11-28 14:51:25 +08:00
..
2025-11-28 14:51:25 +08:00
2025-11-28 14:51:25 +08:00

数据库迁移管理

概述

本目录采用版本化数据库迁移策略,确保数据库结构变更的可追溯性和可回滚性。

目录结构

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初始化(推荐用于新部署)

  1. 迁移脚本按版本号顺序放在 migrations/ 目录
  2. Docker启动时自动执行所有未应用的迁移
  3. 执行记录保存在 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;

版本发布流程

开发阶段

  1. 创建新的迁移文件:V2.0.4__add_feature.sql
  2. 本地测试迁移脚本
  3. 创建对应回滚脚本:R2.0.4__rollback.sql
  4. 测试回滚脚本

构建阶段

  1. 更新 .env 中的版本号
  2. 构建新的 MySQL 镜像(包含最新迁移脚本)
  3. 测试镜像部署和迁移

生产部署

  1. 备份当前数据库
  2. 部署新镜像
  3. 自动应用迁移
  4. 验证迁移结果
  5. 如有问题执行回滚

最佳实践

  1. 小步迭代:每个迁移文件只包含少量相关变更
  2. 向后兼容:新版本应能兼容旧数据
  3. 测试优先:在测试环境充分测试后再生产部署
  4. 备份策略:每次迁移前自动备份
  5. 文档完整:迁移脚本包含详细注释
  6. 版本锁定:明确记录迁移依赖的版本

故障恢复

迁移失败

# 查看失败原因
./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 了解完整示例。