校园图书借阅系统 —— 高校图书馆数字化借阅与智能推荐平台
面向高校图书馆的全栈借阅平台:用确定性锁顺序消除并发死锁、用 FIFO 闭环状态机管理孤本预约、用库存感知的多路加权做推荐,后端 248 + 前端 96 用例,含 3 个并发硬断言。
角色 独立开发:后端 / Flutter 前端 / 容器化交付 / 文档与部署
面向高校图书馆的全栈数字化借阅平台,分读者、馆员、系统管理员三种角色:读者端做多维检索、混合 AI 推荐(内容偏好 + 行为偏好 + 热度 + 在架库存多路加权)、一键借阅与孤本预约排队;馆员端做实体副本管理、条码扫码还书与 Excel 流式批量编目;管理端提供运营大盘与权限审计。
工程上重点解决三件事:高并发借还的一致性(确定性锁顺序消除死锁)、FIFO 预约闭环状态机、以及「结构化元数据约束 + 本地规则降级」的 AI 导读引擎。后端 248 个用例、前端 96 个用例,其中 3 个是并发硬断言用例;交付为 Docker Compose 一键起全栈。
并发超借与循环死锁:选课周、考试季大量学生同时抢热门教材时,借书锁父表、还书锁子表会互相等待,把连接池打爆并产生负库存超借。
预约流程无序、资源僵化:书籍借出后没有透明的排队位次,归还后无法自动定向流转,逾期未取又造成馆藏闲置。
推荐脱离库存、大模型幻觉:通用推荐不了解真实物理库存,推荐出来却借不到;直接引入外部大模型还会编造书目,并因长时网络 I/O 长期占用数据库连接。
高可靠:借还流通在高并发下不超借、不死锁,预约排队闭环可追踪、可自动流转。
高性能:编目导入支持大数据量且内存占用恒定;AI 能力与数据库事务物理解耦,外部依赖抖动不拖垮全站。
易交付:一套 Docker Compose 起全栈(PostgreSQL + Redis + 后端 + 前端 + Nginx 网关),镜像体积与安全基线可控。
借还流通引擎不依赖乐观锁或单机同步锁,而是把借书与还书两条链路的加锁顺序统一成确定的顺序,从根上破坏死锁的循环等待条件,再用并发硬断言用例把结论固定下来。
预约做成闭环状态机:归还事件主动唤醒队首读者,超时未取自动淘汰并顺延下一顺位,资源不在队列里僵死。
推荐把真实在架库存作为权重的一路,并过滤无库存书目,避免推荐了却借不到;AI 导读用结构化元数据约束输出范围,未配置 Key 时降级到本地规则引擎。
交付侧多阶段构建、非 root 运行、Nginx 网关统一入口,CanvasKit 与中文字体全部同源自托管,脱网也能正确渲染。
Flutter Web / Desktop / App 客户端(Riverpod 单向数据流、Material 3 响应式布局)经 Nginx 网关(静态资源 + SPA history 路由 + Gzip + SSL 终止)访问 Spring Boot 3.3 服务(生产镜像用 JDK 21,启用分代 ZGC)。后端包含 Spring Security + JWT 无状态鉴权(RBAC:读者 / 馆员 / 管理员)、借还流通引擎(确定性顺序行级悲观排他锁)、FIFO 闭环预约状态机、多路加权推荐、双模 AI 导读、EasyExcel SAX 流式编目解析;数据面为 PostgreSQL 17(Flyway V1–V17 迁移)与 Redis 8,全链路带 TraceId 与结构化日志。
把借书锁父表、还书锁子表的互相等待统一为确定的加锁顺序(行级悲观排他锁),从根上破坏死锁的循环等待条件;并用并发硬断言守住:50 借 + 50 还交叉争抢同一批副本,超借数断言为 0。
归还事件主动唤醒队首读者,超时未取自动淘汰并顺延下一顺位,资源不会在队列里僵死。
推荐请求先读真实库存,命中「推荐了却借不到」的体验黑洞;权重由内容偏好、行为偏好、热度与在架状态共同决定。
导读生成用结构化元数据约束输出(限定在真实书目字段内),并把外部 LLM 调用与数据库事务物理解耦;未配置 Key 时自动降级为本地规则引擎。
EasyExcel SAX 模式流式解析,内存占用 O(1),不随行数增长。
多阶段构建把镜像裁到后端 150 MiB / 前端 39 MiB,容器非 root 运行;Flyway 17 个版本连续迁移;CanvasKit 与中文字体全部同源自托管,不依赖公共 CDN,脱网也能正确渲染。
并发控制方式
选了 确定性顺序的行级悲观排他锁,而不是 乐观锁重试或单机同步锁 —— 循环等待可以通过统一加锁顺序直接消除,不依赖重试策略,也不引入单机状态。
代价:加锁顺序成为必须遵守的全局约定,后续涉及库存的新代码要专门评审。
AI 导读的实现方式
选了 云端 LLM 与本地规则引擎双模,并按超时降级,而不是 只依赖云端模型 —— 外部依赖的可用性不可控,长 I/O 不能占用数据库连接,且没有 Key 时功能也应可用。
代价:需要维护两套生成逻辑,并单独设计降级判定与提示。
前端交付形态
选了 Flutter 一套代码覆盖 Web / Desktop / App,而不是 为每个端单独写一套界面 —— 个人项目要控制维护成本,跨端复用能显著减少重复实现。
代价:Web 端首屏体积明显大于纯原生前端方案,需要用自托管与按需加载来补偿。
后端测试:248 / 248 通过(61 个测试类,0 失败 / 0 错误 / 0 跳过);前端测试:96 / 96 通过(23 个测试文件),flutter analyze 无问题。
并发硬断言(不是描述性文字):50 借 + 50 还交叉争抢 → 超借 0;50 线程抢单册副本 → 库存不足拦截恰好 49;100 线程预约同一孤本 → 排位 1~100 唯一不重复。
数据库迁移:Flyway V1–V17 连续迁移无偏差,当前 schema 版本 v17;生产镜像体积为后端 150 MiB / 前端 39 MiB(多阶段构建 + 非 root 运行)。
线上部署(2026-09-23 实测):实例首页返回 HTTP 200 且标题为「校园图书借阅系统」;/actuator/health 返回 {"status":"UP","groups":["liveness","readiness"]};业务接口在未携带 token 时返回 401(中文错误信息 + traceId),说明鉴权链路正常。自 2026-09-24 起该实例通过 https://library.myiskg.com/ 提供访问。
仓库:GitHub 公开仓库(Apache-2.0),25 次提交,最新提交 2026-09-22,含源码、设计文档与部署指南。
交付物:Docker Compose 生产编排(多阶段构建、非 root、Nginx 网关)、一键启停脚本、10 份设计文档(需求 / 总体设计 / 数据库 / API / 权限 / 统计 / AI 模块 / 测试方案)与 Stage0–Stage10 阶段报告、深度审计报告与生产部署指南。
并发问题靠描述说不清:把「不超借」写成断言,才让结论可验证、回归可守住,也让设计意图不会被后来的人改回去。
推荐系统的可用性也是正确性的一部分:算法再准,推荐了借不到的书,用户感受到的就是功能坏了。
外部依赖必须假定它会失败或变慢:把它移出事务边界、并准备一个能独立工作的降级分支,比提高调用成功率更可靠。






