签入版本
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
# 数据库迁移工具使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
`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 等
|
||||
Reference in New Issue
Block a user