Files
2026-09-11 11:39:07 +08:00

9.5 KiB
Raw Permalink Blame History

数据库迁移工具使用说明

概述

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 读取

迁移流程

  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 参数指定需要继续迁移的表:

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版本)

  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 等