feat: 建立 MySQL 8 数据库基础 (#78)
This commit is contained in:
@@ -13,13 +13,12 @@
|
||||
|---|---|---|
|
||||
| Go | **1.23.0** | `go version` 输出 `go version go1.23.0 windows/amd64` |
|
||||
| Git | 任意较新版本 | `git --version` 有输出 |
|
||||
| DB Browser for SQLite | 任意 | 用来看数据库,可选但强烈建议装 |
|
||||
| MySQL Client | 8.4 | 用于连接独立的 MySQL 8.4 开发/测试库 |
|
||||
|
||||
版本已定为 **go1.23.0**,写在 `admin/go.mod` 里。低于这个版本可能编译不过。
|
||||
|
||||
**不需要装 gcc。** 本项目的 SQLite 驱动是纯 Go 实现的
|
||||
(`modernc.org/sqlite`),不依赖 cgo,这也是选它的原因——
|
||||
`go build` 直接出单个 exe,不用配 C 编译器。
|
||||
**不需要装 gcc。** 生产 MySQL 驱动和历史 SQLite 迁移驱动都是纯 Go;
|
||||
`go build` 不依赖 C 编译器。
|
||||
|
||||
## 2. 拉依赖
|
||||
|
||||
@@ -47,6 +46,7 @@ go mod download
|
||||
```powershell
|
||||
go get github.com/gin-gonic/gin@v1.11.0
|
||||
go get modernc.org/sqlite@v1.38.0
|
||||
go get github.com/go-sql-driver/mysql@v1.9.2
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
@@ -57,13 +57,13 @@ go mod tidy
|
||||
go get github.com/xuri/excelize/v2@v2.9.1
|
||||
```
|
||||
|
||||
这三个是**在 Go 1.23.0 下实测能编译通过的最高版本**,
|
||||
这些是在 Go 1.23.0 下实测能编译通过的固定版本,
|
||||
为什么不能更高见 [admin/AGENTS.md](../../admin/AGENTS.md) 技术栈一节。
|
||||
|
||||
`[必须]` `go.mod` 和 `go.sum` 都要提交 Git,否则别人拉下来版本对不上。
|
||||
|
||||
> SQLite 驱动**不要**换成 `mattn/go-sqlite3`,那个需要 cgo,
|
||||
> 得装 gcc,还会让 `go build` 出不了单文件 exe。
|
||||
> `go-sql-driver/mysql` v1.9.3 起要求 Go 1.24,本项目固定 v1.9.2。
|
||||
> SQLite 驱动只用于历史库迁移,仍不要换成需要 cgo 的 `mattn/go-sqlite3`。
|
||||
|
||||
## 3. 跑起来
|
||||
|
||||
@@ -157,21 +157,34 @@ syb:
|
||||
| `database is locked` | 有别的程序占着数据库 | 关掉 DB Browser 再试;程序运行时只读打开是可以的 |
|
||||
| 导入 Excel 报错但没说哪一行 | 解析器没带行号 | 这是 bug,报错必须带行号,见 [06](06-quality-security.md) §2 |
|
||||
|
||||
## 6. 数据库在哪、怎么看
|
||||
## 6. 数据库在哪里、怎样配置
|
||||
|
||||
跟 Client 一样是**便携模式**——数据都在程序旁边的 `data/` 里:
|
||||
生产数据在 MySQL 8.4 中。Admin 从环境变量读取连接信息:
|
||||
|
||||
```text
|
||||
CMAUTOBUY_DB_HOST=127.0.0.1
|
||||
CMAUTOBUY_DB_PORT=3307
|
||||
CMAUTOBUY_DB_NAME=<独立数据库名>
|
||||
CMAUTOBUY_DB_USER=<最小权限账号>
|
||||
CMAUTOBUY_DB_PASSWORD=<只保存在服务器环境文件中的密码>
|
||||
```
|
||||
|
||||
密码不得写入 `config.yaml`、仓库、日志或工单。线上 MySQL 只监听本机,
|
||||
本地开发通过 SSH 隧道连接独立的 `_test` 数据库。
|
||||
|
||||
程序旁边的 `data/` 只保留日志、上传文件和迁移前的 SQLite 只读备份:
|
||||
|
||||
```text
|
||||
admin/data/
|
||||
├── admin.db 数据库
|
||||
├── backup/ 迁移前的 admin.db 只读备份
|
||||
├── logs/ 运行日志
|
||||
└── uploads/ 上传的 Excel 原件
|
||||
```
|
||||
|
||||
跑源码时在 `admin\data\`;将来打包成 exe 后,在 exe 旁边。
|
||||
|
||||
用 **DB Browser for SQLite** 打开 `admin.db` 就能看数据。
|
||||
每张表什么意思见 [03 数据模型](03-data-model.md)。
|
||||
每张表什么意思见 [03 数据模型](03-data-model.md)。旧 `admin.db` 只能通过
|
||||
单向迁移命令读取,生产 Admin 不再直接打开它。
|
||||
|
||||
> 写代码时**不要自己拼这个路径**,用统一的 `DataDir()` 函数,
|
||||
> 见 [02 架构](02-architecture.md) §6。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
- 文档状态:基线草案,待需求评审
|
||||
- 适用范围:`admin/`
|
||||
- 产品类型:本地运行的 Web 管理端(Go + Gin + HTML 模板)
|
||||
- 产品类型:集中部署的 Web 管理端(Go + Gin + HTML 模板 + MySQL 8.4)
|
||||
|
||||
本文档中 `[必须]` / `[建议]` / `[待定]` 的含义见 [文档索引](../README.md#文档标注说明)。
|
||||
没有标注的默认是 `[必须]`。看不懂的词查 [术语表](00-glossary.md)。
|
||||
@@ -410,7 +410,7 @@ PDD 商品之所以单独一个模块,是因为它在数据上就是**独立
|
||||
MVP 包含:
|
||||
|
||||
- 五模块页面框架和统一的三段式布局;
|
||||
- SQLite 建库与迁移;
|
||||
- MySQL 8.4 建库与追加式迁移;SQLite 仅作为一次性历史数据迁移来源;
|
||||
- 蝦皮 Excel 导入(upsert)、搜索、批量删除、手动新增、编辑弹窗;
|
||||
- PDD 链接录入与发起采集;
|
||||
- 顺运宝数据的**手工录入或造数**(同步按钮占位);
|
||||
@@ -441,7 +441,7 @@ MVP 之后:
|
||||
|
||||
## 10. 非功能需求
|
||||
|
||||
- 单机运行,操作人员规模是个位数,不追求高并发。
|
||||
- 集中部署,操作人员规模是个位数;不追求大规模并发,但任务领取必须保证并发唯一。
|
||||
- 页面在 1366×768 上可正常使用。
|
||||
- 导入 1 万行 Excel 应在可接受时间内完成,并显示进度或结果统计。
|
||||
- 所有写操作有 CSRF 防护,所有 SQL 参数化。
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
└───────────────────────┬──────────────────────┘
|
||||
│
|
||||
┌───────────────────────▼──────────────────────┐
|
||||
│ repository SQLite 读写 │
|
||||
│ repository MySQL 8 读写 │
|
||||
│ 只有这一层能写 SQL │
|
||||
└───────────────────────┬──────────────────────┘
|
||||
│
|
||||
@@ -162,7 +162,7 @@ templates/
|
||||
|
||||
```text
|
||||
data/
|
||||
├── admin.db SQLite 数据库
|
||||
├── backup/ 迁移前 SQLite 只读备份
|
||||
├── logs/ 运行日志
|
||||
└── uploads/ 上传的 Excel 原件
|
||||
```
|
||||
@@ -212,7 +212,8 @@ func DataDir() (string, error) {
|
||||
| 直接用 `os.Getwd()` | 双击 exe 和命令行启动,当前目录不一样 |
|
||||
| 往 exe 所在目录写日志但不建 `data/` | 打包后和程序文件混在一起,升级时会被删 |
|
||||
|
||||
`[必须]` 升级方式:换掉 exe,**`data/` 原样保留**。所以数据库必须支持迁移,见 [03](03-data-model.md) §2。
|
||||
`[必须]` 升级时保留 `data/`,并先备份 MySQL。数据库结构通过 MySQL
|
||||
`schema_migrations` 只追加升级,见 [03](03-data-model.md) §2。
|
||||
|
||||
## 7. 请求流程示例
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# 03 Admin 数据模型
|
||||
|
||||
- 文档状态:基线草案,待数据评审
|
||||
- 数据库:SQLite(驱动 `modernc.org/sqlite`,纯 Go 免 cgo)
|
||||
- 位置:`data/admin.db`,见 [02 架构](02-architecture.md) §6
|
||||
- 生产数据库:MySQL 8.4(驱动 `go-sql-driver/mysql` v1.9.2)
|
||||
- 位置:与 Admin 同机的 `127.0.0.1:3307`,使用独立数据库和最小权限账号
|
||||
- 历史数据库:`data/admin.db` 只作为 SQLite → MySQL 单向迁移来源和回退备份
|
||||
|
||||
本文档中 `[必须]` / `[建议]` / `[待定]` 的含义见 [文档索引](../README.md#文档标注说明)。
|
||||
没有标注的默认是 `[必须]`。看不懂的词查 [术语表](00-glossary.md)。
|
||||
@@ -19,6 +20,13 @@
|
||||
|
||||
## 2. 建库与迁移
|
||||
|
||||
生产 MySQL 使用 `schema_migrations` 记录追加版本。MySQL DDL 会隐式提交,
|
||||
因此每条 DDL 必须可重放;整版全部执行、通过表和关键列自检后才记录版本。
|
||||
连接会话固定 UTC,字符集固定 `utf8mb4`,业务 ID 使用二进制排序规则保持大小写精确。
|
||||
|
||||
下面的 PRAGMA 和 `user_version` 章节是历史 SQLite 迁移规则,只供单向迁移工具维护,
|
||||
不得重新接入生产运行时。
|
||||
|
||||
### 2.1 PRAGMA 必须写在 DSN 里
|
||||
|
||||
`[必须]` 三条设置通过**连接串**传入,**不要**用 `db.Exec("PRAGMA ...")`:
|
||||
@@ -444,7 +452,7 @@ CREATE INDEX idx_syb_orders_list ON syb_orders(updated_at DESC, syb_id DESC);
|
||||
|
||||
- `price_twd_cent` 是**台币分**,是蝦皮那边的售价,
|
||||
和采购任务的人民币价格上限**没有换算关系**,不要互相赋值。
|
||||
- `image_url` 存 URL。`[必须]` 不要把图片二进制存进 SQLite。
|
||||
- `image_url` 存 URL。`[必须]` 不要把图片二进制存进数据库。
|
||||
- `shopee_sku_id` **直接对应 `shopee_skus.sku_id`**,编号格式一致,不需要额外转换。
|
||||
|
||||
`[必须]` 但**不要加外键约束**。理由:蝦皮报表不是全量目录(样本里平均每商品仅 1.17 个 SKU),
|
||||
@@ -713,7 +721,7 @@ users(采购员)──1:N 当前归属──────────┘
|
||||
|
||||
## 11. 与 Client 数据模型的关系
|
||||
|
||||
Admin 和 Client **各有一个 SQLite,互不相通**,只通过接口交换数据。
|
||||
Admin 使用集中 MySQL 8.4,Client 仍使用各自的本地 SQLite;两者只通过接口交换数据。
|
||||
|
||||
| 概念 | Admin 这边 | Client 那边 |
|
||||
|---|---|---|
|
||||
@@ -744,7 +752,7 @@ CREATE TABLE users (
|
||||
|
||||
- `password_hash` 只保存成熟密码哈希算法的结果,绝不保存或记录明文密码。
|
||||
- 用户不做物理删除;离职或停用改为 `disabled`,保留任务和操作记录的可追溯性。
|
||||
- 首次初始化必须在写事务中再次确认 `users` 为空;SQLite 同一时刻只有一个写事务,
|
||||
- 首次初始化必须在 InnoDB 写事务中锁定初始化保护记录并再次确认 `users` 为空,
|
||||
并发提交最多一个成功。即使所有账号都被禁用,初始化入口也不能重新开放。
|
||||
- 系统不能禁用最后一个有效管理员。
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
### 2.2 集成测试
|
||||
|
||||
用临时 SQLite 覆盖:
|
||||
用独立、库名以 `_test` 结尾的真实 MySQL 8.4 测试库覆盖:
|
||||
|
||||
- 完整导入 → 建采集任务 → 模拟 Client 提交结果 → `collect_status` 变 `collected`;
|
||||
- 并发 `claim`:两个客户端同时领,只有一个拿到;
|
||||
@@ -93,7 +93,8 @@
|
||||
| 迁移前备份或用可回滚步骤 | `data/` 在升级时保留,迁移失败会毁掉全部历史 |
|
||||
| **不得在启动时删库重建** | 同上 |
|
||||
|
||||
`[建议]` 导入前自动把 `admin.db` 复制一份到 `data/backup/`,保留最近几份。
|
||||
`[必须]` 生产变更前执行 MySQL 备份;SQLite 最终迁移前把 `admin.db` 复制到
|
||||
`data/backup/` 并保持只读,至少保留到生产验收完成。
|
||||
|
||||
## 4. Web 安全
|
||||
|
||||
@@ -166,7 +167,7 @@
|
||||
|
||||
## 7. 性能
|
||||
|
||||
规模很小(个位数操作员、单机运行),不要提前优化。但下面几条是基本功:
|
||||
规模很小(个位数操作员、集中部署),不要提前优化。但下面几条是基本功:
|
||||
|
||||
- `[必须]` 搜索、排序、分页走**数据库查询**,不要一次查全量再在内存里过滤。
|
||||
- `[必须]` 常用查询有索引(见 [03 数据模型](03-data-model.md) 里的 `CREATE INDEX`)。
|
||||
@@ -182,7 +183,7 @@
|
||||
| 3 | `go test ./...` 全绿 | 不允许有跳过而未说明的用例 | 开发者 |
|
||||
| 4 | 五个页面能正常打开 | 起服务跑一遍 | 开发者 |
|
||||
| 5 | 样本导入条数正确 | 导入参考样本(需向项目负责人索取,放 `raw_data/`),应得 5195 商品 + 6092 SKU | 开发者 |
|
||||
| 6 | 数据库从上一版本迁移成功 | 拿旧 `admin.db` 副本启动新版本,人工数据不丢 | 开发者 |
|
||||
| 6 | 数据库升级和 SQLite 单向迁移成功 | 隔离 MySQL 升级通过;旧 `admin.db` 迁移后逐表核对一致 | 开发者 |
|
||||
| 7 | 契约测试通过 | [04 §9 清单](04-client-api.md)逐条 | 开发者 |
|
||||
| 8 | 干净环境启动 | 没装过本项目的机器上 `go run .` 或跑 exe | 开发者 |
|
||||
| 9 | 日志和页面无敏感信息 | 翻一遍 `data/logs/` | 开发者 |
|
||||
@@ -194,6 +195,9 @@
|
||||
|
||||
第 10 项开发者**不要自己判断放行**,把包名和许可证类型报给项目负责人。
|
||||
|
||||
当前新增生产数据库驱动:`github.com/go-sql-driver/mysql` v1.9.2,许可证
|
||||
**MPL-2.0**。技术验证通过不代表许可证已获发布批准,仍需项目负责人确认门禁 10。
|
||||
|
||||
## 9. 打包
|
||||
|
||||
`[待定]` 打包动作属于 MVP 之后,但策略现在定下来:
|
||||
@@ -203,7 +207,7 @@
|
||||
- 模板和静态文件用 `//go:embed` 打进 exe,**不要散在外面**,
|
||||
否则用户可能改坏或删掉;
|
||||
- `data/` 留在 exe 旁边,**升级时保留**,见 [02 架构](02-architecture.md) §6;
|
||||
- 升级方式:换掉 exe,`data/` 不动,靠 `PRAGMA user_version` 自动迁移。
|
||||
- 升级方式:替换服务程序,先备份 MySQL,再由 `schema_migrations` 追加升级。
|
||||
|
||||
产出目录:
|
||||
|
||||
@@ -211,7 +215,7 @@
|
||||
CMAutoBuyAdmin/
|
||||
├── admin.exe 单文件,模板和静态资源都在里面
|
||||
└── data/ 数据,升级时保留
|
||||
├── admin.db
|
||||
├── backup/ 迁移前 SQLite 只读备份
|
||||
├── logs/
|
||||
└── uploads/
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user