Files
easygoadmin-wiki/EasyGoAdmin_GoFrame_NaiveVue/zh/tools/db-migrate.md
T
2026-10-20 21:53:26 +08:00

132 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 7.6 数据库迁移工具
:::tip 概述
整库迁移器(internal/migrate + cmd/migrator)实现五方言互迁:源库内省 → 中间表示 → 目标方言 DDL → 分批搬运 → 序列修复 → 行数校验。纯 CLI、gdb 动态建连裸读裸写(不走 dao,不触发全局钩子)。
:::
## 五阶段流程
```text
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 1/5 建目标库│──▶│ 2/5 建表结构│──▶│ 3/5 搬运数据│──▶│ 4/5 序列修复│──▶│ 5/5 行数校验│
│ ensureDB │ │ 内省→建表 │ │ 分批 INSERT│ │ setval等 │ │ COUNT 对比 │
│ (不存在才建)│ │ →建索引 │ │ 进度回调 │ │ │ │ PASS/FAIL │
└────────────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
drop-first: 无主键表报错跳过 pgsql/mssql 专项 不一致→
先 DropAllTables 其余方言免修 整体失败
非清空: 同名表拦截跳过
```
## CLI 参数
```sh
go run ./cmd/migrator \
-src-type=mysql -src-host=127.0.0.1 -src-hostport=3306 \
-src-database=easygoadmin.goframe.elevue -src-username=root -src-password=root \
-dst-type=pgsql -dst-host=127.0.0.1 -dst-hostport=5432 \
-dst-database=easygoadmin.goframe.elevue -dst-username=postgres -dst-password=123456 \
-drop-target-first
```
| 参数组 | 键 | 默认 |
|--------|-----|------|
| 源库 | -src-type / host / hostport / database / username / password | mysql / 127.0.0.1 / 3306 / — / root / — |
| 目标库 | -dst-type / host / hostport / database / username / password | pgsql / 127.0.0.1 / 5432 / — / postgres / — |
| 行为 | -drop-target-first | 迁移前清空目标库**全部表**(慎用) |
| | -tables | 只迁指定表(逗号分隔白名单,留空迁全部) |
| | -batch-size | 数据搬运批大小(默认 1000) |
## 核心设计
```text
独立于业务基座:
gdb.New 动态连接源库与目标库(独立命名节点 migrate_src/migrate_dst,
不触碰 config.yaml 默认连接),裸读裸写——
全程不触发全局钩子(租户隔离/软删/审计盖章),数据原样落库
五方言目标渲染器(Renderer 接口:Quote/Column/CreateTable/CreateIndex/
DropAllTables/FixSequence):
mysql AUTO_INCREMENT + COMMENT 内联
pgsql IDENTITY + COMMENT ON 独立语句 + setval 序列修复 + CASCADE
sqlite 极简类型 + AUTOINCREMENT + 免修序
mssql IDENTITY + NVARCHAR + 扩展属性注释 + 内联 INSERT(绕 2100 参数上限)
+ DBCC CHECKIDENT 修序
oracle IDENTITY + NUMBER/NVARCHAR2 + COMMENT ON + 免修序
中间表示(IR):20 种归一类型;剥离 unsigned/pgsql 时区修饰;
tinyint(1)→bool;索引命名统一 uk_/idx_ 规范(迁移后全库一种命名)
数据搬运 doCopy:主键游标分页;无主键表直接报错("请先补主键")
```
## 数据搬运循环图(doCopy,主键游标分页)
```text
lastPK=nil
│
▼
┌──────────────────────────────────────────┐
│ SELECT 列集 FROM src.table │
│ WHERE pk > lastPK ORDER BY pk LIMIT N │◀──────┐
└──────────────┬───────────────────────────┘ │
行数=0?─ 是 ─▶ 返回 total │
否 │
▼ │
batch=[{列:值(字节转字符串)}…],lastPK=末行 pk ────┘
│
▼
目标写入:通用方言 → 参数化多行 INSERT
mssql → 内联字面量 INSERT(自增列:事务内 IDENTITY_INSERT ON/OFF)
│
▼
total += len(batch);onBatch 进度回调;len(batch)<N → 结束
```
要点:源端按主键排序快照分页(快照语义,并发写入可能漂移);字节切片值转字符串(convertValue);mssql 因 2100 参数占位符上限走内联字面量 + 单批小事务(IDENTITY_INSERT ON→INSERT→OFF→COMMIT)。
## 关键原则与限制
::: warning 限制清单
1. 无外键/视图/存储过程/触发器迁移(0 外键设计,只迁表/列/二级索引/注释/数据)
2. 无主键表拒绝搬运(分页搬运依赖主键排序)
3. mssql/oracle 源端索引内省未实现(作为源库时二级索引会丢)
4. 逐表串行搬运(无并发),超大库耗时线性增长
5. `-drop-target-first` 清空目标库**全部表**(含非本项目表),慎用
6. 逐表行数校验不一致 → 整体失败退出码 1
:::
## 与五方言定稿脚本的关系
```text
document/{mysql,postgresql,sqlserver,oracle,sqlite}/easygoadmin.goframe.elevue.sql
= "定稿 DDL"(mysql 为规范基准,人工导入维护)
迁移器 = "运行期动态等价物"(自动跟随源库结构)
两者独立演进:新表/新索引需两边同步(DDL 脚本手工维护)
```
## 实测记录
仓库保留实测日志(可参考排障):
```text
document/数据迁移PostgreSQL版本日志.txt
document/数据迁移SqlServer版本日志.txt
document/数据迁移Sqlite版本日志.txt
document/数据迁移命令.txt(完整参数说明与示例)
```
首期实测链路 mysql→pgsql;mssql/oracle 按定稿方言约定实现,待人工校对。
## 使用建议
```text
1. 迁移前备份源库与目标库
2. 首次迁移用 -tables 白名单先迁小表验证连通与方言转换
3. 全量迁移加 -drop-target-first(确认目标库无他用!)
4. 观察每表行数校验 PASS/FAIL;FAIL 表排查后 -tables 单独重迁
5. 迁移后核对索引(uk_* 命名已统一)与注释(非 MySQL 目标语义可能降级)
6. 应用侧切库:改 config.yaml database.default.type/link 重启
```