feat: 实现 SQLite 到 MySQL 单向迁移 (#80)

This commit is contained in:
chengma
2026-08-10 02:40:14 +08:00
parent 86b9e696de
commit c296feaf74
7 changed files with 671 additions and 2 deletions
+2
View File
@@ -50,6 +50,7 @@
| 加字段、改表、写 SQL | [03 数据模型](admin/03-data-model.md) | [02 架构](admin/02-architecture.md) §2 分层 |
| 改 Excel 导入 | [03 数据模型](admin/03-data-model.md) §3.3 | [00 术语表](admin/00-glossary.md) §3 upsert |
| 改顺运宝同步 | [08 顺运宝接口](admin/08-顺运宝接口.md) | [03 数据模型](admin/03-data-model.md) |
| 把旧 Admin 数据迁移到 MySQL | [09 SQLite 单向迁移](admin/09-sqlite迁移到mysql.md) | [06 质量与安全](admin/06-quality-security.md) |
| 改给 Client 的接口 | [04 Client 接口实现](admin/04-client-api.md) | [Client 侧契约](client/04-admin-api-contract.md) |
| 和 Admin 联调、登记新设备 | [07 设备登记联调手册](admin/07-设备登记联调手册.md) | [Client 侧契约](client/04-admin-api-contract.md) §5 |
| 写测试 | [06 质量与安全](admin/06-quality-security.md) §2 | — |
@@ -90,6 +91,7 @@
| [06 质量、安全与测试](admin/06-quality-security.md) | 测试、Web 安全、发布门禁 |
| [07 设备登记联调手册](admin/07-设备登记联调手册.md) | **给 Client 开发者**:怎么让新设备登记成功 |
| [08 顺运宝接口](admin/08-顺运宝接口.md) | 从抓包还原的外部 ERP 契约:登录、会话、货运单列表与明细 |
| [09 SQLite 单向迁移](admin/09-sqlite迁移到mysql.md) | 只读演练、一次性导入、逐表核对和失败处理 |
## 文档标注说明
+2 -1
View File
@@ -184,7 +184,8 @@ admin/data/
跑源码时在 `admin\data\`;将来打包成 exe 后,在 exe 旁边。
每张表什么意思见 [03 数据模型](03-data-model.md)。旧 `admin.db` 只能通过
单向迁移命令读取,生产 Admin 不再直接打开它。
单向迁移命令读取,生产 Admin 不再直接打开它。具体操作见
[09 SQLite 单向迁移到 MySQL 8](09-sqlite迁移到mysql.md)。
> 写代码时**不要自己拼这个路径**,用统一的 `DataDir()` 函数,
> 见 [02 架构](02-architecture.md) §6。
+66
View File
@@ -0,0 +1,66 @@
# SQLite 单向迁移到 MySQL 8
这份文档用于把历史 `admin.db` 一次性迁移到新的空 MySQL 8 数据库。迁移不是同步:成功切换后只使用 MySQL,不再把数据写回 SQLite。
## 1. 安全边界
- 源 `admin.db` 必须是 schema v8;工具使用操作系统只读模式和 SQLite `query_only` 打开。
- 目标必须是本程序刚建立且业务表为空的独立 MySQL 数据库;任何业务表非空都会拒绝执行。
- 不支持覆盖、合并、双写和重复导入。重新演练时新建另一个空测试库。
- 数据库密码只放环境变量,不要写入命令历史、仓库、日志或工单。
- 输出只包含表名和数量,不包含账号、Cookie、Session、订单号或商品明细。
## 2. 迁移前准备
先停止旧 Admin 的写入,复制一份只读备份,并记录哈希。以下命令从 `admin/` 目录执行:
```powershell
New-Item -ItemType Directory -Force data\backup
Copy-Item data\admin.db data\backup\admin-before-mysql.db
Get-FileHash data\admin.db -Algorithm SHA256
```
由数据库管理员提前创建独立的空数据库和最小权限账号。按部署环境设置这五个变量:
```powershell
$env:CMAUTOBUY_DB_HOST="127.0.0.1"
$env:CMAUTOBUY_DB_PORT="3307"
$env:CMAUTOBUY_DB_NAME="<空数据库名>"
$env:CMAUTOBUY_DB_USER="<迁移账号>"
$env:CMAUTOBUY_DB_PASSWORD="<从安全渠道取得>"
```
## 3. 先演练
```powershell
go run ./cmd/migrate-sqlite-to-mysql --source data/admin.db --dry-run
```
预期第一行是“演练检查通过,未写入数据”,后面只显示 15 张业务表的数量。此时 MySQL 业务表仍为空。
## 4. 执行并独立复核
```powershell
go run ./cmd/migrate-sqlite-to-mysql --source data/admin.db --execute
go run ./cmd/migrate-sqlite-to-mysql --source data/admin.db --verify-only
Get-FileHash data\admin.db -Algorithm SHA256
```
`--execute` 在一个 MySQL 事务中导入全部业务表,然后比较源、目标的逐表数量和全列摘要。`--verify-only` 再独立读取两边核对一次。最后的 SQLite 哈希应与迁移前一致。
## 5. 失败时怎样处理
- “SQLite schema 必须是 v8”:先用旧版本 Admin 的迁移逻辑把备份副本升级到 v8,不要直接改 `user_version`。
- “MySQL 目标不是空库”:停止操作,换一个新的空数据库;不要手工清表后继续生产迁移。
- “无法写入 MySQL”或“数量或内容摘要不一致”:不要启动新 Admin;保留源库和迁移前备份,丢弃本次目标库,修复原因后在新的空库重演。
- 迁移失败会回滚业务数据;MySQL schema 建表是可重放的,但业务数据绝不能部分保留后继续补写。
## 6. 切换门禁
只有下面各项都完成后才能让生产 Admin 使用新库:
- 演练、正式迁移和 `--verify-only` 均通过;
- SQLite 文件哈希迁移前后相同;
- MySQL 已备份,Admin 环境变量由系统服务安全注入;
- 页面登录、蝦皮/PDD/顺运宝列表、客户端领取和一次演练模式采购任务冒烟通过;
- 旧 `admin.db` 保留为只读回退证据,不再由 Admin 打开。