# 数据库迁移工具使用说明 ## 概述 `migrate_db.py` 是一个跨数据库迁移工具,支持将数据从 MySQL 迁移到 PostgreSQL、SQL Server、SQLite、Oracle 等数据库。 ## 核心设计 **参考FastAPI版本的设计思路:** - 使用 SQLAlchemy ORM 模型定义表结构(方言可移植) - 数据按拓扑序逐表迁移,显式带 id 批量插入 - 迁移后按方言重置自增序列 ## 特性 - ✅ 支持 MySQL → PostgreSQL / SQL Server / SQLite / Oracle - ✅ 自动从 Django 模型加载表结构定义 - ✅ 按拓扑序迁移表,保证数据完整性 - ✅ 批量插入,高性能迁移 - ✅ 自动重置自增序列(PG/MSSQL/Oracle) - ✅ 支持干跑模式(dry-run) - ✅ 支持断点续传(--only-tables) - ✅ 迁移后自动校验数据行数 ## 依赖安装 根据目标数据库安装对应的 Python 驱动: ```bash # PostgreSQL pip install psycopg # SQL Server pip install pymssql # Oracle pip install oracledb # MySQL(通常已安装) pip install pymysql ``` ## 使用方法 ### 1. 显式指定源库和目标库 ```bash # MySQL → PostgreSQL python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=postgresql --dst-host=127.0.0.1 --dst-port=5432 \ --dst-db=djangoadmin.django.elevue --dst-user=postgres --dst-pass=postgres # MySQL → SQL Server python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=mssql --dst-host=127.0.0.1 --dst-port=1433 \ --dst-db=djangoadmin --dst-user=sa --dst-pass=your_password # MySQL → SQLite python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=sqlite --dst-db=./data/djangoadmin.db # MySQL → Oracle python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=oracle --dst-host=127.0.0.1 --dst-port=1521 \ --dst-db=ORCL --dst-user=system --dst-pass=oracle ``` ### 2. 使用 .env 配置(如果可用) ```bash # 只需指定目标库,源库从 .env 读取 python scripts/migrate_db.py \ --dst-driver=postgresql --dst-host=127.0.0.1 --dst-port=5432 \ --dst-db=djangoadmin --dst-user=postgres --dst-pass=postgres ``` ### 3. 干跑模式 先查看迁移计划,不实际执行: ```bash python scripts/migrate_db.py --dry-run \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=postgresql --dst-db=djangoadmin \ --dst-user=postgres --dst-pass=postgres ``` 输出示例: ``` [==============================================================] [DRY-RUN 开始] 计划迁移 27 张表 → postgresql:djangoadmin [==============================================================] - django_dept: 31 行 - django_menu: 217 行 - django_role: 21 行 ... [DRY-RUN 完成] 27 张表核对完毕(耗时 1.2s),未触碰目标库 ``` ### 4. 断点续传 如果迁移中断,可以使用 `--only-tables` 继续迁移指定的表: ```bash python scripts/migrate_db.py \ --only-tables=django_user,django_role,django_menu \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=postgresql --dst-host=127.0.0.1 --dst-port=5432 \ --dst-db=djangoadmin.django.elevue --dst-user=postgres --dst-pass=postgres ``` ### 5. 跳过已存在的表 ```bash python scripts/migrate_db.py --skip-existing \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=postgresql --dst-host=127.0.0.1 --dst-port=5432 \ --dst-db=djangoadmin.django.elevue --dst-user=postgres --dst-pass=postgres ``` ## 参数说明 | 参数 | 说明 | 默认值 | |------|------|--------| | `--src-driver` | 源库驱动 | mysql | | `--src-host` | 源库主机 | 127.0.0.1 | | `--src-port` | 源库端口 | 自动识别 | | `--src-db` | 源库名称 | 必填 | | `--src-user` | 源库用户名 | root | | `--src-pass` | 源库密码 | 空 | | `--dst-driver` | 目标库驱动 | 必填 | | `--dst-host` | 目标库主机 | 127.0.0.1 | | `--dst-port` | 目标库端口 | 自动识别 | | `--dst-db` | 目标库名称 | 必填 | | `--dst-user` | 目标库用户名 | postgres | | `--dst-pass` | 目标库密码 | 空 | | `--drop-target-first` | 先删除目标库 | False | | `--dry-run` | 干跑模式 | False | | `--chunk-size` | 每批插入行数 | 1000 | | `--only-tables` | 只迁移指定表 | 空(全部) | | `--skip-existing` | 跳过已存在的表 | False | | `--skip-verify` | 跳过校验 | False | | `--single-transaction` | 单事务模式 | False | | `--prefix` | 表前缀 | 从 .env 读取 | ## 迁移流程 1. **加载模型** - 从 Django 模型加载表结构定义 2. **建目标库** - 自动创建目标数据库(如不存在) 3. **建表结构** - 使用 SQLAlchemy ORM 模型创建表(方言可移植) 4. **迁移数据** - 按拓扑序逐表批量插入数据 5. **重置序列** - 针对 PG/MSSQL/Oracle 重置自增序列 6. **校验数据** - 对比源库和目标库的行数 ## 注意事项 1. **表前缀**:默认使用 `.env` 中的 `DATABASE_PREFIX`(默认为 `django_`) 2. **字符集**:MySQL 使用 utf8mb4,PostgreSQL 使用 UTF8 3. **自增序列**:迁移后会自动重置,确保新数据能正确生成 ID 4. **外键关系**:项目使用裸列引用(无外键约束),按拓扑序迁移可保证引用完整性 5. **软删除**:所有表都包含 `is_delete` 字段,迁移时会保留该字段 ## 常见问题 ### Q: 迁移过程中断怎么办? 使用 `--only-tables` 参数指定需要继续迁移的表: ```bash python scripts/migrate_db.py --only-tables=django_user,django_role ``` ### Q: 如何查看迁移进度? 迁移过程中会显示每个表的迁移进度: ``` [django_user] +100(累计 100) [django_user] +100(累计 200) [✓ django_user] 共 500 行(耗时 1.2s) ``` ### Q: 目标库已存在数据怎么办? 使用 `--drop-target-first` 参数先删除目标库: ```bash python scripts/migrate_db.py --drop-target-first ``` 或者使用 `--skip-existing` 跳过已存在的表: ```bash python scripts/migrate_db.py --skip-existing ``` ### Q: 如何只迁移部分表? 使用 `--only-tables` 参数指定表名(逗号分隔): ```bash python scripts/migrate_db.py --only-tables=django_user,django_role,django_menu ``` ## 示例场景 ### 场景1:开发环境 MySQL → 测试环境 PostgreSQL ```bash python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=postgresql --dst-host=test-db-server --dst-port=5432 \ --dst-db=djangoadmin_test --dst-user=postgres --dst-pass=test_password \ --drop-target-first ``` ### 场景2:生产环境迁移(带校验) ```bash python scripts/migrate_db.py \ --src-driver=mysql --src-host=prod-db-server --src-port=3306 \ --src-db=djangoadmin_prod --src-user=readonly --src-pass=readonly_password \ --dst-driver=postgresql --dst-host=new-db-server --dst-port=5432 \ --dst-db=djangoadmin_prod --dst-user=postgres --dst-pass=new_password \ --chunk-size=5000 ``` ### 场景3:迁移到本地 SQLite(开发调试) ```bash python scripts/migrate_db.py \ --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 \ --src-db=djangoadmin.django.elevue --src-user=root --src-pass=root \ --dst-driver=sqlite --dst-db=./data/debug.db \ --skip-verify ``` ## 技术架构 ### 核心设计(参考FastAPI版本) 1. **模型定义**:使用 SQLAlchemy ORM 定义表结构,保证方言可移植 2. **拓扑排序**:基础表在前,依赖表在后,保证引用完整性 3. **批量插入**:显式带 id 插入,保住裸列引用关系 4. **序列重置**:按方言重置自增序列(PG setval / MSSQL DBCC CHECKIDENT / Oracle sequence+trigger) ### 与 FastAPI 版本的差异 | 特性 | FastAPI版本 | Django版本 | |------|------------|------------| | 模型来源 | SQLAlchemy ORM 模型 | Django 模型动态转换 | | 配置来源 | core.config | config.env | | 表前缀 | 从配置读取 | 从Django配置读取 | | 模型加载 | 直接导入 | 动态创建 | ## 成功案例 ``` [迁移开始] 源: mysql:djangoadmin.django.elevue → 目标: postgresql:djangoadmin.django.elevue [迁移开始] 待迁移 35 张表 [✓] [1/5] 建目标库 完成(耗时 62ms) [✓] [2/5] 建表结构(35 张表 create_all) 完成(耗时 74ms) [✓] [3/5] 逐表迁移数据 完成(耗时 37.5s),共 784612 行 [✓] [4/5] 重置自增序列 完成(耗时 2.2s) [✓] [5/5] 逐表行数校验 完成(耗时 605ms),35 张表全部 PASS [迁移完成] 成功:784612 行 / 35 张表 / 总耗时 40.8s ``` **迁移的35张表包括:** - Django内置表(11张):auth_permission, auth_group, auth_user, auth_group_permissions, auth_user_groups, auth_user_user_permissions, django_content_type, django_migrations, django_session, django_admin_log, captcha_captchastore - 项目业务表(24张):django_dept, django_menu, django_role, django_user, django_city 等