03. 验证数据并创建只读账号
1. 本章目标
导入命令没有报错,只能说明工具完成了流程,不能证明数据与应用预期一致。本章验证表、规模、结构和关键数据语义,然后建立 airportdb_training 与只读应用账号。
2. 确认实际 schema 名
进入 MySQL:
sudo mysql
查看数据库:
SHOW DATABASES;
以下示例使用 airportdb_training。如果导入结果叫 airportdb,有两个选择:
- 保持
airportdb,把服务器.env的DB_NAME配置为它; - 保留它作为只读基准库,再复制出
airportdb_training用于索引实验。
复制五千多万行数据会消耗大量时间和磁盘。不要直接执行一个未经评估的复制命令。空间不足时,第一阶段可以只有一个 airportdb_training,同时保留官方 ZIP 和重新导入步骤。
下面假设目标库已经是 airportdb_training:
USE airportdb_training;
3. 验证 14 张表
SHOW TABLES;
SELECT COUNT(*) AS table_count
FROM information_schema.tables
WHERE table_schema = 'airportdb_training'
AND table_type = 'BASE TABLE';
官方资料描述 AirportDB 有 14 张表。下载版本和修复脚本可能不同,所以需要记录实际结果,不能为了凑数而删除或创建表。
查看表状态:
SHOW TABLE STATUS FROM airportdb_training;
InnoDB 的 TABLE_ROWS 是估算值,适合快速了解规模,不等于精确 COUNT(*)。
4. 检查关键表结构
SHOW CREATE TABLE airportdb_training.flight\G
SHOW CREATE TABLE airportdb_training.booking\G
SHOW CREATE TABLE airportdb_training.airport_geo\G
SHOW CREATE TABLE airportdb_training.weatherdata\G
重点记录:
- 主键与外键;
- 列类型和是否允许
NULL; - 已有普通索引和联合索引;
flight中from、to等特殊列名;airport_geo的坐标类型、SRID 和经纬度顺序;weatherdata的复合键和时间字段;booking.price等DECIMAL字段。
应用中的 Sequelize Model 必须映射现有结构,禁止用 sequelize.sync({ force: true }) 或 sequelize.sync({ alter: true }) 修改样本库。
5. 检查数据规模
先用表状态估算,随后仅对必须记录的关键表执行精确计数:
SELECT COUNT(*) AS airport_count FROM airport;
SELECT COUNT(*) AS flight_count FROM flight;
SELECT COUNT(*) AS booking_count FROM booking;
SELECT COUNT(*) AS weather_count FROM weatherdata;
booking 的精确计数可能需要较长时间。第一次执行前可在另一个会话观察:
SHOW FULL PROCESSLIST;
如果只是判断数据是否存在,优先使用有限查询:
SELECT * FROM booking LIMIT 5;
不要在应用的 /health 中执行大表 COUNT(*)。健康检查只验证数据库能否响应轻量连接或查询。
6. 验证日期和坐标
检查航班日期范围:
SELECT MIN(departure) AS min_departure,
MAX(departure) AS max_departure
FROM flight;
检查天气时间范围:
SELECT MIN(log_date) AS min_log_date,
MAX(log_date) AS max_log_date
FROM weatherdata;
实际列名以 SHOW CREATE TABLE 为准。如果示例列不存在,先根据表结构调整,不要猜测并修改数据库。
检查机场坐标样本:
SELECT *
FROM airport_geo
LIMIT 10;
若包含 POINT,使用与实际列名对应的 ST_X()、ST_Y() 检查。必须通过已知机场验证 X/Y 分别代表经度还是纬度,不要仅凭经验假设。
7. 创建只读应用账号
7.1 为什么单独创建账号
后端只需要查询数据。若 .env 泄露或程序有缺陷,只读权限可以降低删除或修改样本数据的风险。Node.js 应用绝不能使用 root。
生成一个强随机密码。可以在服务器上执行:
openssl rand -base64 32
进入 MySQL,以实际密码替换 <强随机密码>:
CREATE USER 'airport_app'@'127.0.0.1'
IDENTIFIED BY '<强随机密码>';
GRANT SELECT
ON airportdb_training.*
TO 'airport_app'@'127.0.0.1';
SHOW GRANTS FOR 'airport_app'@'127.0.0.1';
MySQL 把 'airport_app'@'127.0.0.1' 与 'airport_app'@'localhost' 视为不同账号。本项目 .env 使用 DB_HOST=127.0.0.1,所以创建相同 host 部分的账号最清楚。
如果账号已经存在,应先检查权限,不要反复执行 CREATE USER。更换密码使用:
ALTER USER 'airport_app'@'127.0.0.1'
IDENTIFIED BY '<新的强随机密码>';
8. 验证账号确实只读
退出管理员会话:
EXIT;
使用应用账号连接:
mysql -h 127.0.0.1 -u airport_app -p airportdb_training
验证读取:
SELECT COUNT(*) FROM airport;
SHOW GRANTS;
在训练环境中验证写入被拒绝,可以执行一个不会成功的事务:
START TRANSACTION;
UPDATE airport SET name = name LIMIT 1;
ROLLBACK;
预期 UPDATE 返回权限错误。不要为了测试权限而授予写权限。
9. 配置项目环境变量
在项目目录:
cd /var/www/airport-operations-explorer
cp .env.example server/.env
chmod 600 server/.env
编辑 server/.env:
NODE_ENV=production
HOST=127.0.0.1
PORT=3000
CLIENT_ORIGIN=https://airport.cxhair.cn
LOG_LEVEL=info
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=airportdb_training
DB_USER=airport_app
DB_PASSWORD=<强随机密码>
DB_POOL_MAX=10
DB_HEALTH_TIMEOUT_MS=2000
server/.env 已被 .gitignore 排除。不要把内容粘贴到 issue、日志或 Git 提交中。
10. 使用项目健康检查验证
安装并构建后端:
npm ci
npm run build -w server
npm start -w server
在另一个 SSH 会话:
curl -i http://127.0.0.1:3000/health
正常响应应是 HTTP 200,并包含:
{
"data": {
"status": "ok",
"database": {
"status": "up"
}
}
}
如果返回 503:
- 检查
server/.env是否位于正确目录; - 手工使用相同账号连接 MySQL;
- 检查
DB_HOST、DB_NAME和账号 host 部分; - 查看后端日志,但不要把密码打印出来。
验证后按 Ctrl+C 停止前台进程。第 5 章会用 PM2 正式管理它。
11. 本章验收
- 实际表数量与关键表结构已经记录;
- 日期、坐标和金额类型经过检查;
airport_app只能SELECT;server/.env权限为 600 且未进入 Git;/health显示数据库为up。