1
Database Operations
biss edited this page 2026-07-24 12:00:48 +08:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

数据库与数据工具

本页包含会修改数据的命令。执行前先确认目标数据库、停止应用并完成备份。示例命令不会在阅读 Wiki 时自动执行。

1. 支持的数据库

数据库 推荐场景 特点
SQLite 本地开发、测试、演示、单机部署 单文件、零外部依赖
MySQL 8.4 生产、多实例、集中运维 独立服务、连接池、并发能力更强

应用启动时会初始化空库结构和基础配置,但不会自动导入学校、考生、考试或报名等演示业务数据。

当前结构版本是 v20。已有数据库版本低于 v20 时,应用会拒绝直接运行并要求先备份和执行明确的升级流程。

2. 数据库目标识别

应用根目录通常是包含 Eis.slnx.env 的目录。

SQLite

  • 默认:<应用根目录>/data/exam.sqlite
  • SQLITE_PATH 相对路径:按应用根目录解析
  • --path:数据库工具命令的显式 SQLite 目标

MySQL

  • DATABASE_URL 优先;
  • 否则读取 MYSQL_HOSTMYSQL_PORTMYSQL_USERMYSQL_PASSWORDMYSQL_DATABASE
  • 数据库工具确认目标时使用数据库名,不是主机名。

执行任何写操作前,先记录工具输出中的“目标”一行。

3. 建立 MySQL 数据库和账号

示例:

CREATE DATABASE exam_information
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_0900_ai_ci;

CREATE USER 'exam_app'@'%'
  IDENTIFIED BY 'replace-with-a-strong-password';

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER
  ON exam_information.*
  TO 'exam_app'@'%';

应用需要创建和演进表结构,因此账号除了数据读写外还需要 CREATEALTER。不要授予 MySQL 全局管理员权限。

配置方式见配置参考

4. 数据库结构

主要关系表包括:

  • 组织:organizationschoolsschool_classes
  • 用户:userscandidate_profiles
  • 考试:examsexam_subjects
  • 报名:registrationsregistration_subjects
  • 编排:test_centerstest_roomsexam_arrangement_plansadmit_cardsadmit_card_subjects
  • 成绩:results
  • 流程:workflow_definitionsworkflow_stepsworkflow_instancesworkflow_actions
  • 报名号:number_rulesnumber_rule_segmentscandidate_account_batchescandidate_account_batch_items
  • 招生:招生计划、志愿、投档、录取、报到及相关记录
  • 公告与审计:noticesaudit_logs
  • 分表登记:exam_data_partitionsschool_student_partitions
  • 版本:schema_metadata

系统还为每场考试和每所学校维护专属物理分表。不要只备份总表或只复制少数业务表。

5. 获取数据库工具

统一发布:

pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1

工具位于:

artifacts/publish/tools/Eis.Tools.dll

查看帮助:

dotnet .\artifacts\publish\tools\Eis.Tools.dll --help

源码开发时也可以:

dotnet run --project .\src\Eis.Tools\Eis.Tools.csproj -- --help

6. 命令概览

database init   非破坏性建表和基础配置初始化
database reset  重建为空业务库
database seed   导入内置 1200 名考生演示数据

通用参数:

参数 说明
--sqlite 明确使用 SQLite
--mysql 明确使用 MySQL
--path <文件> SQLite 文件路径,只能与 --sqlite 一起使用
--confirm-target <目标> 对破坏性命令确认最终目标
--force 仅 MySQL;允许覆盖无法识别为内置演示数据的业务数据
--dry-run 只预检,不写入
--root <目录> 指定 .env 和相对 SQLite 路径的应用根目录

--sqlite--mysql 不能同时使用。database init 不接受 --force

7. 初始化空库

SQLite

dotnet .\artifacts\publish\tools\Eis.Tools.dll database init `
  --sqlite `
  --path .\data\exam.sqlite

MySQL

先配置 .env 或进程环境变量,然后:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database init --mysql

init 是非破坏性操作,用于建表和基础配置。它不会导入演示学校、考生或考试。

8. 导入演示数据

演示数据内置于 Eis.Infrastructure.dll,生产服务器不需要 Node.js。

SQLite 安全流程

第一步,只预检:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
  --sqlite `
  --path .\data\demo.sqlite `
  --dry-run

第二步,核对工具显示的绝对目标路径。

第三步,明确确认同一目标:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
  --sqlite `
  --path .\data\demo.sqlite `
  --confirm-target .\data\demo.sqlite

如果目标文件已存在,工具先复制为:

<数据库文件>.backup-<UTC时间戳>

MySQL 测试库安全流程

第一步:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed --mysql --dry-run

确认输出的数据库名确实是测试库,例如 exam_test

第二步:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
  --mysql `
  --confirm-target exam_test

如果工具发现无法识别为内置演示数据的业务记录,会拒绝覆盖。只有在已经备份且确认这个测试库可以完全覆盖时才使用:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
  --mysql `
  --confirm-target exam_test `
  --force

--force 不会删除数据库本身,但会改写其中的应用数据。不得对生产业务库使用。

9. 演示账号

演示数据中的预置账号密码统一为 12345678

角色 账号
超级管理员 admin
超级管理员(监督演示) supervisor
校级管理员 school_admin
同校校级管理员 school_admin_2
班级管理员 class_admin
同班班级管理员 class_admin_2
考生 2026-HZ01-F-0001

这些账号只存在于演示数据。正常启动空库时不会创建校级、班级或考生样例账号。

10. 测试结束后重建空系统

SQLite

先停止应用:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset `
  --sqlite `
  --path .\data\exam.sqlite `
  --confirm-target .\data\exam.sqlite

工具自动备份原 SQLite 文件,然后建立 v20 空业务系统和初始超级管理员。

MySQL

先预检:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset --mysql --dry-run

再确认测试数据库名:

dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset `
  --mysql `
  --confirm-target exam_test

目标包含非演示业务数据时会拒绝。即使使用 --force,也应先完成 MySQL 原生备份。

11. Docker 中维护 SQLite

Compose 默认数据库路径是 /app/data/exam.sqlite,保存在命名卷 exam-information-data

先停止 Web

docker compose stop app

再运行工具,目标和确认路径必须完全一致:

docker compose run --rm --entrypoint dotnet app `
  /app/tools/Eis.Tools.dll database seed `
  --sqlite `
  --path /app/data/exam.sqlite `
  --confirm-target /app/data/exam.sqlite

完成后启动:

docker compose up --detach app

不要对容器内另一个临时路径执行 seed 后误以为已经修改命名卷数据库。

12. 备份与恢复建议

SQLite

维护前:

  1. 停止所有使用该文件的 Web 和工具进程。
  2. 记录数据库绝对路径。
  3. 复制数据库文件到独立备份目录。
  4. 保留工具自动生成的时间戳备份。
  5. 恢复时先停止应用,再用备份文件替换目标。

不要只复制 -wal-shm 文件。应用运行时直接复制数据库可能得到不一致备份,应优先停机。

MySQL

使用组织既有的 MySQL 备份方案,例如逻辑备份、快照或托管服务备份。至少验证:

  • 备份包含全部表和结构;
  • 恢复到隔离测试库成功;
  • 字符集为 utf8mb4
  • 应用账号权限仍正确;
  • 恢复库结构版本是 v20。

13. 安全保护

数据库工具会:

  • 要求破坏性命令明确 --confirm-target
  • SQLite 比较最终绝对路径;
  • MySQL 比较数据库名;
  • 拒绝 mysqlinformation_schemaperformance_schemasys 等系统库;
  • 校验演示数据和数据库结构版本;
  • 默认拒绝覆盖未知 MySQL 业务数据;
  • 为已有 SQLite 文件自动建立时间戳备份。

这些保护不能代替人工确认和外部备份。

14. 常见错误

“这是破坏性操作”

缺少 --confirm-target,或确认值和最终目标不一致。重新查看工具输出,不要盲目复制旧命令。

“数据库结构版本低于要求”

当前应用要求 v20。停止上线,保留完整备份,并执行针对旧版本的升级流程;不要用 reset 假装完成生产迁移。

“MySQL 配置不完整”

设置完整 DATABASE_URL,或至少设置 MYSQL_HOSTMYSQL_USERMYSQL_DATABASE

“拒绝覆盖非演示业务数据”

目标中存在工具无法确认可覆盖的数据。先核对是否选错库。只有确认是可完全覆盖的测试库并已备份时才考虑 --force

SQLite 文件没有变化

检查:

  • --path 是否指向预期文件;
  • 相对路径按哪个 --root 解析;
  • 容器中是否使用 /app/data/exam.sqlite
  • Web 是否仍在运行并占用或继续写另一个数据库。