9.5 KiB
9.5 KiB
数据库迁移工具使用说明
概述
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 驱动:
# PostgreSQL
pip install psycopg
# SQL Server
pip install pymssql
# Oracle
pip install oracledb
# MySQL(通常已安装)
pip install pymysql
使用方法
1. 显式指定源库和目标库
# 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 配置(如果可用)
# 只需指定目标库,源库从 .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. 干跑模式
先查看迁移计划,不实际执行:
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 继续迁移指定的表:
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. 跳过已存在的表
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 读取 |
迁移流程
- 加载模型 - 从 Django 模型加载表结构定义
- 建目标库 - 自动创建目标数据库(如不存在)
- 建表结构 - 使用 SQLAlchemy ORM 模型创建表(方言可移植)
- 迁移数据 - 按拓扑序逐表批量插入数据
- 重置序列 - 针对 PG/MSSQL/Oracle 重置自增序列
- 校验数据 - 对比源库和目标库的行数
注意事项
- 表前缀:默认使用
.env中的DATABASE_PREFIX(默认为django_) - 字符集:MySQL 使用 utf8mb4,PostgreSQL 使用 UTF8
- 自增序列:迁移后会自动重置,确保新数据能正确生成 ID
- 外键关系:项目使用裸列引用(无外键约束),按拓扑序迁移可保证引用完整性
- 软删除:所有表都包含
is_delete字段,迁移时会保留该字段
常见问题
Q: 迁移过程中断怎么办?
使用 --only-tables 参数指定需要继续迁移的表:
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 参数先删除目标库:
python scripts/migrate_db.py --drop-target-first
或者使用 --skip-existing 跳过已存在的表:
python scripts/migrate_db.py --skip-existing
Q: 如何只迁移部分表?
使用 --only-tables 参数指定表名(逗号分隔):
python scripts/migrate_db.py --only-tables=django_user,django_role,django_menu
示例场景
场景1:开发环境 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=test-db-server --dst-port=5432 \
--dst-db=djangoadmin_test --dst-user=postgres --dst-pass=test_password \
--drop-target-first
场景2:生产环境迁移(带校验)
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(开发调试)
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版本)
- 模型定义:使用 SQLAlchemy ORM 定义表结构,保证方言可移植
- 拓扑排序:基础表在前,依赖表在后,保证引用完整性
- 批量插入:显式带 id 插入,保住裸列引用关系
- 序列重置:按方言重置自增序列(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 等