在整理毕设选题时,很多同学会把“爱心书屋管理系统”“公益图书借阅平台”这类题目当成普通的CRUD项目来做,最后交上去的代码无非是几张表的增删改查,答辩时被老师一问“并发借阅怎么处理”“逾期状态如何流转”“捐赠图书怎么入库审核”,场面就非常被动。这个项目看似只有一个温馨的公益主题,背后其实藏着完整的业务闭环:图书的入库、上架、借阅、归还、预约、捐赠、审核、逾期计费、数据统计。如果只按教材套路做,很容易做成“图书馆管理系统的换皮版”。
这个基于SpringBoot的爱心书屋管理系统,核心定位是“社区共享书屋的数字化运营平台”,它既要像普通图书管理系统一样管好图书,又要解决公益场景特有的问题——图书来源多样(个人捐赠、机构赠送、采购)、借阅规则灵活(免费借阅、积分激励、信用管理)、面向人群复杂(社区居民、志愿者、管理员)。我见过不少这个方向的毕设代码,真正能落地的版本,架构上一般会选择SpringBoot + MyBatis-Plus + MySQL + Redis的组合,前端用Vue或者Thymeleaf,鉴权用JWT,整个系统的核心难点不在某个单一技术,而在“借阅状态机的设计”和“捐赠到入库的业务闭环”,这两块能讲清楚,答辩基本就稳了。
无论你是打算直接参考这套设计自己写一遍,还是接手了别人代码想彻底弄懂,这篇文章都会把一个合格的公益图书借阅平台应该怎么拆、怎么做、怎么避坑,一条条掰开讲清楚。
1. 项目全貌与设计思路拆解
1.1 公益书屋项目到底要解决什么问题
很多社区书屋、校园爱心书角,日常运营停留在“手写登记表 + Excel台账”的阶段。我调研过几个实际运营的书屋,最典型的痛点有三个:
第一,图书去向不可追踪。一本书被谁借走了、借了多久、有没有还回来,全靠纸面记录,书丢了根本查不到责任环节。
第二,捐赠和库存管理脱节。热心人捐了书,管理员登记不及时,或者图书品相太差、内容不适合上架,缺乏审核环节,导致书架上堆了一堆没人借的旧书。
第三,借阅规则执行难。公益书屋通常是免费借阅,但“免费”不代表“无限期”,超期不还、图书破损、预约冲突这些问题,靠人工去提醒和处理非常吃力。
数字化运营系统要解决的,不是“把登记表变成网页”,而是把借阅流程、捐赠流程、库存流程、用户激励流程全部在线化,并且让管理员能一眼看出:哪些书受欢迎、哪些书积压、谁在长期借书不还、哪位捐赠者的书质量最高。
1.2 为什么选SpringBoot做底座
选SpringBoot不是因为它“热门”,而是因为它刚好匹配这个项目的全部诉求。毕设项目要求周期短、见效快、技术栈完整,SpringBoot的自动配置能让开发第一天就能跑起来页面;内置的Spring MVC和事务管理,天然适合处理“借书-扣库存-生成记录”这种事务性业务;配合MyBatis-Plus,单表操作几乎不用写SQL,把精力留给核心业务逻辑。
对比一下其他方案:SSH(Struts2 + Spring + Hibernate)已经明显过时,配置繁琐且社区资源少;纯Servlet/JSP虽然能体现基础功,但开发效率太低,页面和逻辑耦合严重;如果上微服务或者Spring Cloud,对毕设来说过度设计,面试官和答辩老师更希望看到你把单机项目做扎实。SpringBoot恰好卡在“够用、好用、能讲清楚”的位置。
1.3 整体架构三看
这个项目的架构不需要复杂,但层次必须清晰。我建议按下面的方式组织:
- 表现层:前端页面 + 后端Controller,负责参数接收、权限校验、数据回显
- 业务层:Service接口 + 实现类,负责借阅规则、库存扣减、积分计算等核心逻辑
- 数据层:Mapper接口 + 实体类,负责数据库读写
- 基础设施:MySQL存业务数据,Redis存验证码、Token、热门图书缓存
前端方案上,如果时间紧张就选Thymeleaf服务端渲染,一套SpringBoot就能跑完,省去跨域和前后端联调的麻烦;如果想把项目档次拉高一点,用Vue3 + Element Plus做前后端分离,后端只出JSON接口,工作量会大一些,但展示效果更好。我个人建议毕设阶段优先考虑前后端分离,因为这个项目的接口设计本身就不复杂,分离以后代码结构更清楚,答辩讲起来逻辑更顺。
1.4 角色权限的划分要点
公益书屋和普通管理系统最大的不同在于角色多。我习惯分成四个角色:
- 系统管理员:管理后台全部功能,包括用户管理、图书审核、数据统计、系统配置
- 书屋管理员(店长角色):负责图书入库、上架、下架、处理借阅异常、审核捐赠
- 普通用户:可以浏览图书、借阅、预约、续借、捐赠图书、发表书评
- 游客:只能看图书列表和公告,不能借阅
权限控制用Spring Security或者简单粗暴的拦截器都能做。如果用的是Spring Security,配合注解@PreAuthorize可以优雅地控制接口权限;如果项目比较小,用拦截器+用户角色字段也能实现,但接口层一定要校验,不能用“前端隐藏按钮”来代替后端权限。
2. 核心功能模块与业务闭环拆解
2.1 图书全生命周期管理
这个功能听起来简单,但要做好需要把图书状态设计清楚。一本图书在系统里会经历多个状态:可借、借出、预约中、下架、待审核、损坏、遗失。
我见过很多人把状态设计成一个字符串字段,然后在代码里到处写if判断,比如if("1".equals(status)),这种做法后续改起来极其痛苦。正确做法是定义枚举或者常量类,每个状态的含义和流转条件写清楚。
图书管理模块至少要覆盖以下操作:
- 图书录入:手动录入或扫码录入,包含ISBN、书名、作者、出版社、分类、封面、馆藏数量
- 状态变更:上架、下架、标记损坏、标记遗失
- 库存调整:库存数量、可借数量、预约数量的联动
- 图书检索:按书名、作者、ISBN、分类检索,支持模糊查询和分页
一个容易忽略的点是“馆藏数量”和“可借数量”并不是同一个概念。总馆藏可能是5本,当前有2本被借走、1本被预约、2本可借。库存扣减的逻辑必须在借阅事务里完成,不能用简单的“数量减一”,要判断可借数量是否大于0,否则就是超借。
2.2 借阅流程是核心中的核心
借阅业务看上去是“用户点借书,系统扣库存”,实际上一套完整的借阅流程包含以下环节:
- 用户发起借书请求
- 系统校验:用户是否登录、状态是否正常、是否有逾期未还的图书、该图书是否可借
- 原子操作:可借数量减一、图书状态变为借出、生成借阅记录、借书日期写入
- 借阅成功后,如果有其他用户在排队预约,通知下一顺位用户
- 到期前系统自动发送提醒(站内信、邮件或短信)
还书流程同样要小心:归还时检查图书是否损坏、是否逾期,逾期要计算滞纳金或扣除积分,图书状态改回可借,同时触发预约队列判断——如果有人预约,这本书要优先分配给预约用户。
这里最考验功底的是并发控制。试想两个用户同时点击借阅最后一本书,如果不做处理,两个请求都读到“可借数量=1”,然后各生成一条借阅记录,库存就变成负数了。解决方案有三种:
- 悲观锁:在查询图书时加上
SELECT ... FOR UPDATE,锁住这行记录直到事务提交 - 乐观锁:给图书表增加版本号字段,更新时校验版本号,不匹配则重试或提示用户
- Redis分布式锁:适合前后端分离架构,但毕设阶段容易过度设计
我建议优先用乐观锁。它实现简单、性能也好,只需要在更新语句里多一个条件WHERE version = #{oldVersion},更新受影响行数为0就说明冲突了,直接提示“手慢了,图书已被借走”。答辩时能把这个讲清楚,是很亮眼的加分项。
2.3 捐赠管理:公益特色的关键模块
公益书屋和普通图书馆最大的区别在于“书从哪来”。普通图书馆的书是采购的,公益书屋的书很大比例来自社区居民、爱心企业捐赠。这类场景需要一个完整的捐赠流程:
用户在前端提交捐赠申请,填写书名、作者、ISBN、品相、捐赠寄语,有条件的话上传书的照片。管理员在后台收到申请后,需要审核:
- 是否适合上架(教材教辅、非法出版物、严重破损的书都不适合)
- 品相是否达标(至少七成新)
- 是否已有同款图书,如果库存充足可以考虑放入“暂存库”或者转增其他书屋
审核通过后,捐赠记录的状态变为“已入库”,并增加对应图书的馆藏数量。这里要注意:如果系统里已经存在同ISBN的图书,不应该新建一条图书记录,而应该在原记录上增加库存数量;如果不存在,才新建图书档案。
捐赠模块还有一个容易忽略的价值——数据展示。公益平台通常会有“爱心榜”,统计每位捐赠者的捐赠数量和积分。这个可以用捐赠记录表按捐赠人分组统计来实现,不需要额外的表。捐赠者获得的积分可以用于兑换借阅权益或者纪念品,这样就形成了“捐赠—积分—借阅”的完整激励闭环。
2.4 用户激励与信用体系设计
公益书屋虽然没有商业收费压力,但用户管理同样需要“胡萝卜加大棒”的逻辑。
胡萝卜是积分系统。用户每天签到可以获得积分,借书按时归还得积分,捐赠图书按品相和数量得积分,发表优质书评被点赞也能得积分。积分可以用来预约热门图书时插队,或者兑换书屋定制的文创产品。
大棒是信用系统。逾期归还扣信用分,信用分低于某个阈值就限制借阅。图书损坏、遗失更是要扣分甚至暂停借阅资格。
积分和信用最好单独建表,不要塞在用户表的字段里。单独建表方便以后扩展积分明细、信用变更历史,也方便统计。借阅记录表里其实已经包含了“是否逾期”“是否按时归还”的信息,信用分可以从借阅记录里聚合计算,积分明细表则记录每一次积分变动的来源和去向。
2.5 数据统计与可视化
管理员后台一定要有数据看板,否则这个系统“运营”两个字就落不了地。看板至少要包含:
- 图书总量、可借总量、借出总量、预约总量
- 今日新增注册、今日借书数、今日还书数
- 热门图书排行榜(按借阅次数)
- 分类借阅分布(饼图或柱状图)
- 逾期未还清单
如果前后端分离,图表推荐ECharts,后端提供统计接口,前端绘制图表。写统计SQL时要注意:借阅记录表是核心表,按时间范围、状态、图书ID分组统计即可,尽量不要在大表上做多表嵌套查询,可以先查出基础数据,在Java内存中做二次聚合。
3. 数据库设计与技术要点
3.1 核心表设计
我不列完整的建表语句,但把核心表的字段设计和关联关系讲清楚。整个系统最少需要七张表:
用户表(user):id、用户名、密码、昵称、头像、手机号、角色、积分、信用分、状态、注册时间。密码必须加密存储,推荐BCrypt。注意角色字段不建议存字符串“admin”,用数字或者枚举更规范。
图书表(book):id、书名、作者、出版社、ISBN、分类ID、封面URL、简介、总库存、可借库存、状态、入库时间。ISBN建议建立索引,因为这是检索高频字段。总库存和可借库存要区分开,原因前面讲过了。
分类表(category):id、分类名称、父分类ID。虽然公益书屋书的数量不会特别大,但分类还是很必要的,不然用户在书海里检索会崩溃。
借阅记录表(borrow_record):id、用户ID、图书ID、借书时间、应还时间、实际还书时间、状态(借阅中、已归还、已逾期、已续借)、续借次数。这张表是系统中的大表,借阅时间、状态都要建索引。
预约表(reservation):id、用户ID、图书ID、预约时间、状态(等待中、已通知、已取消、已完成)。当图书被还回来时,要查询这张表找到排队中的第一个用户。
捐赠表(donation):id、用户ID、图书ID、数量、品相、捐赠寄语、状态(待审核、已入库、已拒绝)、审核人、审核时间。
积分明细表(credit_log):id、用户ID、变动类型(签到、借书、还书、捐赠、逾期待)、变动值、备注、创建时间。
3.2 表关系的关联思路
用户和图书是多对多关系,通过借阅记录表关联。捐赠表和图书表通过图书ID关联,一个捐赠可能对应一本书的多个副本。预约表可以看作借阅的前置状态,结束时要么取消,要么转换成借阅记录。
事务设计上要小心。整个借书过程是一个事务,但是Redis缓存更新不能在数据库事务里做,否则Redis挂了数据库也会失败。正确的做法是先提交数据库事务,再删除缓存,下一次读取时再回填。这就是经典的Cache Aside Pattern,毕设里如果能主动讲出来,印象分很高。
3.3 状态流转的代码表达
图书状态这种多分支流转,最容易写出又臭又长的if-else。我的建议是做一个简单的状态机工具,或者至少把所有状态常量集中管理:
public enum BookStatus { AVAILABLE("可借", 0), BORROWED("借出", 1), RESERVED("预约中", 2), OFF_SHELF("已下架", 3), PENDING_REVIEW("待审核", 4), DAMAGED("损坏", 5), LOST("遗失", 6); private final String desc; private final Integer code; }状态流转时,写一个方法专门负责校验“从当前状态能否跳到目标状态”。比如可借状态才能借出,借出状态才能归还,下架状态不能预约。这样哪怕以后新增状态,也只改这一处,不会满项目找魔法数字。
3.4 索引与性能优化基础
毕设数据量不大,但答辩时老师最爱问“数据量大怎么办”。提前做好准备:借阅记录表要在用户ID、图书ID、借书时间、状态这四个字段上建索引;图书表的ISBN、分类ID建索引;预约表的用户ID、图书ID、状态建索引。
查询优化一个常见场景:管理员查“当前借阅中的列表”,一般会写WHERE status = '借阅中'。如果这张表有几十万条记录,这个查询就会走全表扫描。预先在状态字段上建索引,性能会好很多。
缓存策略方面,图书详情、分类列表、热门榜单建议存入Redis,设置5到10分钟的过期时间。每次借还书操作后删除相关缓存。这样既不会出现严重的数据不一致,又能明显提升页面响应速度。
4. 从零到可运行的实操记录
4.1 项目初始化与依赖配置
第一步当然是创建SpringBoot项目。我建议用官方Spring Initializr来生成,选择Spring Boot 2.7.x或者3.x版本,依赖选:Spring Web、MyBatis-Plus(需要手动引入)、MySQL Driver、Redis、Lombok、Validation。
MyBatis-Plus的引入要注意版本兼容,3.5.x版本配Spring Boot 2.x没有问题,配Spring Boot 3.x要注意使用mybatis-plus-spring-boot3-starter这个新坐标,否则启动会直接报错。第一次做这个项目的同学经常在这里卡半天。
配置application.yml时,有几个坑值得提前避开:
- 数据库连接URL务必加上
useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai,否则中文乱码、时间差8小时都会找上门 - Redis配置如果没有单独的服务器,本地一定要装好Redis服务,或者用Docker起一个,否则启动时虽然不会挂,但登录验证码功能会报错
- MyBatis-Plus的
logic-delete-field可以配置全局逻辑删除字段,这样删除图书做的不是物理DELETE,而是update状态字段
4.2 用户登录鉴权实现
登录模块我推荐用JWT。实现流程是:用户输入用户名密码,后端校验通过后生成Token,返回给前端;前端每次请求带上Authorization: Bearer <token>;后端写一个拦截器解析Token,把用户ID和角色放进ThreadLocal或者请求上下文。
如果项目是Thymeleaf单体架构,用Session可能更简单,但前后端分离后JWT是事实标准。JWT的好处是无状态,服务器不需要存会话,缺点是注销登录不方便。毕设场景完全够用。
密码加密一定用BCrypt,不要用MD5。MD5加盐虽然比明文强,但BCrypt的慢哈希特性对暴力破解有更好的抵抗力。Spring Security的BCryptPasswordEncoder可以直接用。
4.3 借书与还书的Service实现
借书Service写得是否专业,往往决定这个项目代码评审的档次。我给出一个核心逻辑的骨架:
@Transactional(rollbackFor = Exception.class) public Boolean borrowBook(Long userId, Long bookId) { // 校验用户状态 User user = userMapper.selectById(userId); if (user == null || user.getStatus() != 1) { throw new BizException("用户不存在或已禁用"); } // 查借阅中的数量,防止并发超借 Long borrowingCount = borrowRecordMapper.selectCount( new LambdaQueryWrapper<BorrowRecord>() .eq(BorrowRecord::getUserId, userId) .eq(BorrowRecord::getStatus, "BORROWING")); if (borrowingCount >= MAX_BORROW_COUNT) { throw new BizException("已达最大借阅数量"); } // 乐观锁扣减库存 Book book = bookMapper.selectById(bookId); if (book == null || book.getAvailableCount() <= 0) { throw new BizException("图书不存在或暂无可借库存"); } int updated = bookMapper.deductStock(bookId, book.getVersion()); if (updated == 0) { throw new BizException("操作太频繁,图书已被借走,请刷新后重试"); } // 生成借阅记录 BorrowRecord record = new BorrowRecord(); record.setUserId(userId); record.setBookId(bookId); record.setBorrowTime(LocalDateTime.now()); record.setDueTime(LocalDateTime.now().plusDays(30)); record.setStatus("BORROWING"); borrowRecordMapper.insert(record); // 写积分明细 creditLogService.addCredit(userId, "BORROW", 5); return true; }注意deductStock对应的SQL是关键,必须写成:
UPDATE book SET available_count = available_count - 1, version = version + 1 WHERE id = #{bookId} AND available_count > 0 AND version = #{version}这条SQL本身就包含了库存校验和乐观锁校验,是防超借的核心。这一处代码能写出这种写法,懂行的老师立刻就能看出你理解并发。
还书流程的顺序刚好相反:先更新借阅记录为已归还,再增加图书可借库存,然后检查预约队列,最后结算积分和信用分。还书一定要在事务里做,不能只更新一边,否则要么书没了记录还在,要么记录还了库存没加。
4.4 管理后台的捐赠审核闭环
捐赠审核的后端逻辑比前台借书要复杂一些,因为涉及到“先有书还是先有捐赠记录”的判断。
前端提交捐赠后,系统先生成一条待审核的捐赠记录。管理员点击审核通过时,后端在同一个事务里做以下步骤:
- 查询系统里是否已存在相同ISBN的图书
- 存在则给这本书的可借库存、总库存同时加1
- 不存在则先创建图书档案,状态设为可借
- 更新捐赠记录状态为“已入库”,记录审核人、审核时间
- 给捐赠者加积分,写入积分明细
这里有个细节,审核驳回时一定要填写驳回理由,并且前端用户能看到驳回原因。不然捐书人满心欢喜提交了申请,结果被默默拒绝,体验很糟糕。驳回理由字段建议放在捐赠表里,用一个小字符串就够。
4.5 预约与续借的边界处理
预约功能容易出bug的地方在于“预约转借阅”的时机。当一本书被还回来时,系统找到排在最前面的预约用户,发送通知,但这本书不能直接自动借给该用户——万一这个用户已经不想借了,或者联系不上呢?所以正确方案是:还书后图书状态变为“待预约取书”,预约用户在规定时间内(比如24小时)手动确认借阅;超时未确认则预约自动取消,图书释放为可借状态,通知下一位预约用户。
续借功能的边界条件是:该用户对这本书没有逾期记录,且续借次数小于限制(比如只能续借1次)。续借的本质是把应还时间向后延长,而不是新开一条借阅记录。实现时只要update借阅记录的应还时间和续借次数即可。
5. 常见问题与排查实录
5.1 并发借阅导致的库存负数
这是最常见的问题,我在帮人调试代码时碰到过无数次。现象是借阅记录只生成了两条,但图书的可借库存变成了-1。原因基本都是更新库存和插入借阅记录不在一个事务里,或者更新使用了set available_count = available_count - 1但没有加where available_count > 0。
排查方法很简单:把应用日志里这两条操作的顺序和SQL打出来看一眼就知道。修复方案就是我前面说的,把库存扣减写成带条件的原子更新,加上事务包裹,必要时在代码里加一个同步锁作为兜底。
5.2 逾期时间计算不准确
逾期判断的核心是“当前时间 > 应还时间”。如果数据库里的应还时间存的是timestamp带时区,而Java代码用LocalDateTime取系统默认时区,就有可能出现8小时的偏差。排查时注意数据库连接URL有没有配置serverTimezone,如果有,确保和服务器时区一致。
还有一个细节:应还时间建议在借书时用now().plusDays(30).withHour(23).withMinute(59).withSecond(59)计算,把截止时间设在当天最后一秒,而不是借书时刻的精确30天后。这样用户的实际体验更好,不会出现“中午借的书,下个月中午12点就到期”的尴尬。
5.3 捐赠入库后图书列表搜索不到
这个问题的典型原因是:管理员在审核捐赠时直接给捐赠表改了状态,但是没有创建或者更新图书表记录。图书列表查询的是book表,捐赠表只是流程表,两者必须联起来看。审核通过的逻辑一定是在事务里同时更新book和donation两张表。还有一个低级错误是ISBN在book表里已经存在,但库存加到了错误的记录上——要按ISBN匹配,不是按书名匹配。
5.4 预约通知要么重复发要么漏发
预约通知的触发点是还书操作。如果还书操作没有放在事务里,还书成功后通知发送失败,就会漏掉。我的建议是:还书事务只处理借阅记录、库存、预约状态这些核心数据,通知消息在事务提交后通过事件机制发布。Spring自带@TransactionalEventListener可以做这事,事务提交后执行发送通知,这样就算通知发送失败也不会回滚还书数据。
5.5 部署上线遇到的前后端联调问题
前后端分离模式下,最容易踩的坑是跨域。后端要配置好CORS,允许前端开发服务器的地址访问。如果部署到生产环境,建议让Nginx统一托管前后端,前端请求走/api前缀,由Nginx反向代理到后端SpringBoot服务,这样就绕开了跨域。
另一个常见坑是接口返回的时间和前端展示的时间相差8小时。解决办法是统一用时间戳或者ISO8601字符串传输,前端再格式化展示,不要在前后端各写一套本地时间转换逻辑。如果图省事,也可以在application.yml里配置Jackson的时区。
5.6 经验速查表
下面把我在实际调试和帮人看代码过程中总结的高频问题整理成一张表,基本覆盖了毕设答辩和后期维护的常见雷区:
| 问题现象 | 根因分析 | 处理方案 |
|---|---|---|
| 图书库存变成负数 | 更新库存无并发保护和条件校验 | 乐观锁或行级锁,扣减条件加available_count > 0 |
| 借阅记录丢失 | 事务未包裹多步数据库操作 | Service方法加@Transactional,回滚条件设为Exception |
| 中文乱码 | 数据库连接未指定utf8 | URL加characterEncoding=utf8,并确认库表本身是utf8mb4 |
| 用户列表分页慢 | 排序字段无索引 | 按创建时间、用户名排序时增加索引 |
| 预约状态混乱 | 状态变更没有统一入口 | 状态机管理所有可能的状态流转路径 |
| 图片上传失败 | 未配置上传路径或大小超限 | application.yml配置multipart大小限制,上传路径使用绝对路径映射 |
| 会话失效频繁 | JWT过期时间太短 | Token有效期建议设24小时,配合Redis做刷新 |
| 接口数据重复 | 缓存和数据库操作顺序错误 | 先更新数据库,再删除缓存而不是先删缓存再更新库 |
6. 项目扩展方向与个人实操体会
6.1 还能往哪些方向延展
如果时间和精力允许,我建议在基础需求之上做两个低成本高回报的扩展。
第一个是“消息通知中心”。目前系统的通知包括逾期提醒、预约成功、捐赠审核结果,这些如果都是用户自己去后台翻,体验很差。做一个简单的站内信表(标题、内容、接收人、已读状态),配合一个定时任务扫描借阅记录,给即将到期的用户发送提醒,整个项目的完整度立刻上一个档次。
第二个是“统计报表导出”。管理员看板上的数据,如果能导出成Excel文件,实用性会明显提升。用EasyExcel或者POI,把借阅统计、图书流通、捐赠汇总做成可下载的报表,答辩时现场演示一下,比口说一百句都有说服力。
6.2 关于这套系统的一些掏心话
我在给这个项目做代码走查和调试的过程中发现,很多同学不是不努力,而是把精力用错了地方。有人花大量时间去调前端样式,有人反复纠结用不用Spring Cloud,却忽视了最核心的借阅库存一致性、捐赠业务闭环、逾期状态流转。实际上,毕设项目考察的是“你能否用软件工程的方法解决一个实际问题”,不是“你会不会用最流行的框架”。
我反复强调的乐观锁扣库存、事务边界划分、状态机管理,这些才是老师希望看到的亮点。它们不需要你写出多惊艳的代码,只需要你在设计数据库和写Service时多想一步“并发会发生什么、数据会不会不一致”。
如果你正在做类似的项目,我的建议是:先把借阅核心链路跑通,把捐赠审核闭环做完,再考虑锦上添花的功能。一个能流畅完成“用户登录—浏览图书—借书—还书—捐赠—审核入库”全流程的系统,已经超过大部分毕设的水平。剩下的时间,哪怕多花在写测试用例和数据初始化脚本上,都比堆砌华而不实的功能有价值。
这个项目做完之后最大的获得感,不应该是“我用了一个热门技术栈”,而是你真正理解了业务流转、数据设计和事务逻辑三者之间如何配合。把这些想清楚了,毕业之后无论做哪类业务系统,都能很快上手。