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. 执行
# ① 建库(注意:这一步不指定默认库,因为库还不存在)
mysql -h<host> -u<user> -p < 00_create_database.sql
# ② 建 13 张 system_* 表 + 灌种子
mysql -h<host> -u<user> -p parking_cloud < 01_system_schema.sql
mysql -h<host> -u<user> -p parking_cloud < 02_system_seed.sql
# ③ 建 679 张存量表
mysql -h<host> -u<user> -p parking_cloud < 03_legacy_schema.sql
# ④ 可选:抽样数据
mysql -h<host> -u<user> -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_ci01的 13 张表逐张显式写COLLATE = utf8mb4_general_ci00除了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 指过去(不改任何配置文件):
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-<timestamp>.jar --spring.profiles.active=local
验收三连:
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分钟上报一次
带来两件事:
- 会真的对外发请求(太极/西城平台、云快充、MQ…)。如果目标机不是该业务的运行环境, 这些请求是多余的,甚至可能干扰外部系统的状态
- 在只建表结构的库上,它们会持续报错刷日志(查存量表无数据、外部地址不通)
这不影响 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 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) |