# parking-cloud · 数据库部署包 > 一句话:在**一台干净的机器**上,只用 `sql/` 下这几个 `.sql`,就能建出一个 > **能把 `parking-server` 跑起来**的库。不追求数据一致性,表结构齐、种子数据在,就够了。 --- ## 1. 文件分工 | 文件 | 内容 | 表数 | 体积 | 必须? | 来源 | |---|---|---:|---:|---|---| | `00_create_database.sql` | 建库 `parking_cloud`(utf8mb4 / general_ci),幂等且自纠 | 0 | 2 KB | ✅ | 手写 | | `01_system_schema.sql` | 13 张 `system_*` 表结构 | 13 | 25 KB | ✅ | 手写(P1) | | `02_system_seed.sql` | `system_*` 种子数据(管理员、菜单、字典、OAuth2 客户端) | — | 14 KB | ✅ | 手写(P1) | | `03_legacy_schema.sql` | **679 张存量表结构**(六库合一后的全部) | 679 | 1.5 MB | ✅ | **生成物** | | `04_legacy_sample.sql` | 679 张存量表的**抽样数据**(595 张有行) | — | 56 MB | ⬜ 可选 | **生成物** | `00 + 01 + 02 + 03 = 692 张表`(679 存量 + 13 新建)。 `03` / `04` 都**不含 `system_*`**,与 `01` / `02` 零重叠。 **只用前四个文件就能跑起来**;`04` 的作用只是"让列表页有东西可看"。 --- ## 2. 前置条件 | 项 | 要求 | |---|---| | MySQL | **5.7 或 8.0 均可**(见 §5) | | Redis | 必须。登录令牌与缓存都走 Redis | | 磁盘 | 脚本本身约 **1.5 MB**(`04` 另占 56 MB)。建出来的库:只建结构 **30.2 MB**,加 `04` 后 **87.2 MB**(实测) | | 账号权限 | 建库 + 建表 + 写数据的普通账号即可,**不需要 `SUPER` / `PROCESS`** | --- ## 3. 执行 ```bash # ① 建库(注意:这一步不指定默认库,因为库还不存在) mysql -h -u -p < 00_create_database.sql # ② 建 13 张 system_* 表 + 灌种子 mysql -h -u -p parking_cloud < 01_system_schema.sql mysql -h -u -p parking_cloud < 02_system_seed.sql # ③ 建 679 张存量表 mysql -h -u -p parking_cloud < 03_legacy_schema.sql # ④ 可选:抽样数据 mysql -h -u -p parking_cloud < 04_legacy_sample.sql ``` 本机实测总耗时 **8 秒**(03 用时 3 s / 04 用时 5 s)。 ⚠️ **`03` 每条都是 `DROP TABLE IF EXISTS` + `CREATE TABLE`**,所以它可重复执行, 但**重跑会清掉这些表里的数据**。对着已有数据的库执行前先想清楚。 --- ## 4. ⚠️ `04` 里有真实生产数据 `04` 是**真实生产库抽出来的行**——含客户**手机号、车牌、姓名**。 - **不随仓库提交**:`.gitignore` 已排除该文件,`git status` 里不该出现它 - **只放开发/测试机**:不要往生产或对外环境灌 - **不需要它也能跑**:`02` 给了 `system_*` 种子,`04` 只影响存量业务表有没有数据 - **密钥类表天然是空的**:21 张含密钥/口令的表(`struct_only_tables.txt`)在本地镜像里 本来就只搬结构,所以 `04` 里它们**一行都没有**——不存在密钥泄漏 --- ## 5. 为什么脚本里写死了排序规则 `utf8mb4_general_ci` **不写死会出事。** `DEFAULT CHARSET = utf8mb4` 而不带 `COLLATE` 时,MySQL 取的是 「该字符集在**本服务端**的默认排序规则」: | 目标服务端 | utf8mb4 默认排序规则 | |---|---| | MySQL 5.7 | `utf8mb4_general_ci` | | MySQL 8.0 / 本地新服务端 | `utf8mb4_0900_ai_ci` | 于是同一套脚本会在不同的机器上建出**两种不同排序规则**的库。更糟的是**同一个库内混用**: `03` 的存量表是写死的 `general_ci`,`01` 如果只写 `CHARSET` 就会落到 `0900_ai_ci`, 两者一旦放在一起比较(跨表 JOIN、字符串 `=`),可能直接 `Illegal mix of collations`。**本地镜像就真实踩中过**:663 / 692 张表、6278 个列的排序规则 当时是 `0900_ai_ci`(存量表 650 张 / 6197 列,`system_*` 13 张 / 81 列),已于 2026-10-10 按本包重建修掉。 所以: - `03` 由生成器**统一写成** `COLLATE=utf8mb4_general_ci` - `01` 的 13 张表**逐张显式**写 `COLLATE = utf8mb4_general_ci` - `00` 除了 `CREATE DATABASE IF NOT EXISTS`,还补了一条 `ALTER DATABASE ... COLLATE`—— 因为 `IF NOT EXISTS` 在库**已存在**时是空操作,**不会**修正它的排序规则 ⚠️ 顺带记一条**看着改了其实没改**的坑:`ALTER TABLE … DEFAULT CHARACTER SET … COLLATE …` **只改表默认值、不动已有列**——跑完那个 `Illegal mix` 照样报(实测)。即已经脏掉的库 **改不回来,只能重建**(或逐表 `CONVERT TO`)。本次处理成"整库重建"而不是打补丁,就是因为这个。 `utf8mb4_0900_ai_ci` 是 MySQL 8.0 专有排序规则,**5.7 上会直接 `Unknown collation` 建表失败**。 生成器里有硬守卫:产出里出现 `0900`、`AUTO_INCREMENT=`、`utf8mb3`、`latin1`、 `CHARSET=utf8`(少了 `mb4`)等任一特征,就**拒绝落盘**。 ⚠️ **诚实说明**:本机只有 MySQL 26.7,**没有 5.7 实例**,所以"能在 5.7 上建"这一条 是**静态守卫**(扫 8.0 专有语法/排序规则)得出的,**没有在真 5.7 上实测过**。 首次往 5.7 目标机部署时,建议先在测试库跑一遍 `03`,看有没有 `Unknown collation`。 --- ## 6. 启动与验收 数据库建好后,用环境变量把 `parking-server` 指过去(**不改任何配置文件**): ```bash export DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=parking_cloud export DB_USERNAME=root DB_PASSWORD='' # 生产环境务必用真实账号 export REDIS_HOST=127.0.0.1 REDIS_PORT=6379 java -jar parking-server-.jar --spring.profiles.active=local ``` 验收三连: ```bash curl -s http://127.0.0.1:48080/actuator/health # 期望 {"status":"UP"},且 db/redis 都是 UP python3 tools/api_smoke.py # 期望「合计 66 条断言,通过 66,失败 0」 curl -s -X POST http://127.0.0.1:48080/admin-api/system/auth/login \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"admin123"}' # 期望 code=0 ``` `api_smoke.py` 覆盖 `/admin-api` 全部 **55 个接口**:读接口给数据、写接口空 body 必须回 400、 6 个导出回真 xlsx、错误路径一律 4xx。**判据是响应体里的 `code`,不是 HTTP 状态码**。 (它会把你从浏览器里挤下线——本项目同一账号只允许一个会话,属既定语义。见脚本头部注释。) --- ## 7. ⚠️ 部署到别的服务器时的已知副作用 **定时任务会自动启动,并主动访问外部系统。** `ParkingServerApplication` 上挂着 `@EnableScheduling`,且**没有任何配置开关**。启动日志里能直接看到: ``` SchedulerTaskPool-1 - 西城半小时刷新token: SchedulerTaskPool-3 - 西城停设备状态20分钟上报一次 ``` 带来两件事: 1. **会真的对外发请求**(太极/西城平台、云快充、MQ…)。如果目标机不是该业务的运行环境, 这些请求是多余的,甚至可能干扰外部系统的状态 2. **在只建表结构的库上,它们会持续报错刷日志**(查存量表无数据、外部地址不通) **这不影响 API 可用**——实测:结构-only 的库上,66 条断言照样全过。 若必须静默,两个办法(都不改共享仓库的代码): - 网络层:目标机不放行这些外部地址的出网 - 代码层:在那个部署专用的构建里注掉 `ParkingServerApplication` 的 `@EnableScheduling` (⚠️ 属于业务改动,需单独评估,不要提交进主干) --- ## 8. 这个包已经验到什么程度 不是"导进去没报错"就算数——做的是**逐列逐索引的等价性比对**: | 检查 | 方法 | 结果 | |---|---|---| | 表数 | `information_schema` 计数 | **692** = 679 + 13 ✅ | | **列** | 14418 行(表/序号/列名/类型/可否空/默认值/extra/注释/字符集/排序规则)逐行 diff | **差异 0** ✅ | | **索引** | 1928 行(索引名/序号/列/唯一性/类型/前缀长度)逐行 diff | **差异 0** ✅ | | **表选项** | 692 行(引擎/行格式/排序规则/建表选项/注释)逐行 diff | **差异 0** ✅ | | **分区** | 146 个分区定义(表/分区名/方式/表达式/边界)逐行 diff | **差异 0** ✅ | | 行数(精确 `COUNT(*)`) | 679 张存量表逐张比对 | **逐张一致** ✅ | | 启动 + 全接口 | 结构-only 库 与 结构+数据 库,各跑 `api_smoke.py` | **66/66 × 2** ✅ | | **往返**(包 → 库 → 包) | 用本包建出库,再拿**该库**跑一次生成器,与发布版逐字节比对 | 表数、**679 条表选项行**、`04` **完全相同**;`03` 只多出 6150 个**列级 `COLLATE`**(由隐式继承改为显式书写),剥掉后**逐字节相同** ✅ | 那些 diff 是**唯一**有意的改动:源库镜像里 663 张表 / 6278 列的 `0900_ai_ci` → 目标 `general_ci`(§5)。 比对时把源库侧做了同样的归一,归一之外**一行差异都没有**。 `system_*` 里有 5 张表的行数对不上(`system_login_log` 53→0、`system_operate_log` 71→0、 两个 token 表 6→0、`system_dict_type` 6→5),**这是对的**:那些是源库里**运行期累积**的 登录/操作日志与令牌行,全新部署本就不该有。种子意义上的表(用户/角色/菜单/组织/字典数据) 行数**分毫不差**。 顺带确认的几件事:存量表**外键 0 个**(所以 `04` 的导入顺序无所谓)、 触发器/视图/存储过程/事件**均为 0**、**5 张分区表**(共 146 个分区)的分区定义**原样保留**。 --- ## 9. 重新生成 `03` / `04` `03` / `04` 是**生成物**,源头是本地那个 679 张表的镜像库 `parking_cloud`。 改了镜像就必须重跑生成器(**不要手改生成物**——下次重跑就没了): ```bash bash sql/tools/gen_deploy_sql.sh # 只出 03 bash sql/tools/gen_deploy_sql.sh --with-data # 03 + 04 ``` 生成器自带自检,任一不满足就**拒绝落盘**(宁可不出文件,也不出去坏文件)。包括: 表数与库内总数对得上、无 `system_*` 混入、无 8.0 专有排序规则、无 `AUTO_INCREMENT=`、 字符集声明已归一、分区表仍是 5 张、**两次生成 md5 一致**(产出可复现)。 可用环境变量覆盖连接参数:`DEPLOY_DB_HOST` / `DEPLOY_DB_PORT` / `DEPLOY_DB_USER` / `DEPLOY_DB_PASSWORD`(走 `MYSQL_PWD`,不上命令行)/ `DEPLOY_DB` / `MYSQL_BIN` / `DUMP_BIN`。 **本地镜像已于 2026-10-10 用本包重建**(`00`→`04`,692 张表、0 处 `0900_ai_ci`), 所以现在重跑生成器是**幂等**的:`03` 的 md5 稳定为 `7f28357dacfb522a1b283a9280b163f5`。 重建前后 `03` 的差别只是列级 `COLLATE` 从隐式继承改成显式书写(干净镜像上 mysqldump 会把每个列的排序规则都打出来),语义不变——验证方式是「剥掉全部列级 `COLLATE` 后两份文件逐字节相同」。 --- ## 10. 已知限制 | 限制 | 说明 | |---|---| | **库名只能是 `parking_cloud`** | `01` / `02` 里有 `USE parking_cloud;` 写死。要换库名,得同时改 `00` 的建库名和这两个文件里的 `USE`(或把那两行删掉、由命令行指定默认库) | | **抽样口径 = 每表最多 500 行** | 这是**本地镜像**的抽样上限,`04` 只是把它导出。想改口径要重跑 `sql/migration/10_dump_legacy.sh`(`SAMPLE=N`)重建镜像后,再重跑生成器 | | **没有一致性保证** | 表间无外键,`04` 是各表独立抽样——够"页面有数据",不够跑对账类逻辑 | | **`04` 含 PII** | 见 §4。它没进版本库,但你要手动拷到别的机器时得自己把关 | | **生产切换用的不是这套** | 本包面向"开发/测试/演示环境"。生产全量切换走 `sql/migration/` 的 `10 / 20 / 98 / 99`,判据是**行数相等**,别混用(见 `sql/migration/README.md`) |