尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于Java+Spring+MySQL的平行志愿录取系统数据库课设实战

发布时间:2026/9/26 14:25:44

资讯中心
01
ARTICLE

基于Java+Spring+MySQL的平行志愿录取系统数据库课设实战

基于Java+Spring+MySQL的平行志愿录取系统数据库课设实战
简介这份资源是广东工业大学数据库课程设计大作业的完整项目包面向高校计算机相关专业学生及需要完成数据库课程设计的开发者核心选题为平行志愿录取系统。项目采用Java、Spring、MySQL与Vue.js构建前后端分离架构可作为课程设计参考模板或二次开发基础。压缩包共195个文件约9.4MB包含40个Java后端源码、50个JavaScript与50个map前端资源、27个CSS样式文件以及2个SQL建表脚本、2个xlsx数据表、5个xml配置和yml、properties等工程配置另附png、jpg、ttf、woff等静态资源与Maven构建脚本结构完整、层次清晰。目前已有11474人学习下载热度较高。读者可从中获取平行志愿录取系统的数据库表结构设计、后端接口实现、前端页面组织方式及完整工程目录参考适合用于课程设计答辩准备、项目复现与数据库建模思路学习。1. 平行志愿录取系统一份能跑通的数据库课设长什么样每年到了数据库课程设计季总有人拿着「学生选课系统」「图书管理系统」的题目发愁——不是不会写 SQL而是不知道一个「像样」的课设该做到什么程度。这份广东工业大学的数据库课程设计大作业选的是「平行志愿录取系统」技术栈是 Java Spring MySQL Vue.js前端构建产物里能看到 chunk-vendors、app 等打包后的 CSS 文件说明前端是正经用 Vue CLI 构建过的不是随手写的静态页。它解决的核心问题是把高考平行志愿的「分数优先、遵循志愿、一轮投档」这套规则用数据库事务和并发控制落地成一个可演示、可答辩的完整系统。适合正在做数据库课设、想找一个有真实业务逻辑而非增删改查堆砌的参考项目的同学也适合想看看「数据库并发锁」在录取场景里怎么用的开发者。2. 平行志愿录取的业务逻辑为什么它不是普通 CRUD2.1 分数优先与遵循志愿的数据库表达平行志愿的投档规则说起来简单把所有考生按分数从高到低排成一队分数高的先投轮到某个考生时按他填报的 A、B、C、D 志愿顺序依次检索哪个学校还有计划余额就投进哪个。但落到数据库层面这里有两个关键点容易被忽略。第一是「分数优先」要求一个全局有序的检索顺序。常见做法是在考生表上建(total_score DESC, student_id ASC)的复合索引同分情况下按考生号排序保证排序结果稳定。如果只按分数排同分考生的顺序在 MySQL 里是不确定的录取结果每次跑都不一样答辩时被问到就尴尬了。第二是「遵循志愿」要求按志愿序号顺序检索。志愿表通常设计成(student_id, college_id, volunteer_order)的结构volunteer_order从 1 开始。检索时对每个考生按volunteer_order升序取志愿找到第一个有计划余额的学校就投档。-- 考生表分数优先的排序基础 CREATE TABLE student ( student_id BIGINT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 考生号, student_name VARCHAR(50) NOT NULL, total_score INT NOT NULL COMMENT 总分, status TINYINT DEFAULT 0 COMMENT 0未投档 1已投档 2已录取, INDEX idx_score (total_score DESC, student_id ASC) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 志愿表遵循志愿的顺序基础 CREATE TABLE volunteer ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, college_id BIGINT NOT NULL, volunteer_order TINYINT NOT NULL COMMENT 志愿序号1-6, UNIQUE KEY uk_student_order (student_id, volunteer_order), INDEX idx_college (college_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;idx_score这个复合索引的字段顺序不能反total_score DESC在前才能让排序走索引uk_student_order唯一约束防止同一个考生填出两个「第 3 志愿」这是数据一致性的底线。idx_college则是为了投档时快速统计某学校已投人数。2.2 投档过程的并发控制锁住计划余额投档的本质是「读学校余额 → 判断是否大于 0 → 减 1 → 写投档记录」这四步必须是一个原子操作。如果两个线程同时读到余额为 1都判断可以投就会超录。这就是数据库并发锁的典型场景。常见做法有两种。一种是在事务里用SELECT ... FOR UPDATE对目标学校的计划行加行锁START TRANSACTION; -- 对学校计划行加排他锁其他事务在此阻塞 SELECT plan_remain FROM college_plan WHERE college_id ? FOR UPDATE; -- 应用层判断 plan_remain 0 后执行 UPDATE college_plan SET plan_remain plan_remain - 1 WHERE college_id ? AND plan_remain 0; INSERT INTO admission_record (student_id, college_id, admit_time) VALUES (?, ?, NOW()); COMMIT;FOR UPDATE锁的是college_plan里对应学校的行粒度是行级不是表级不同学校之间不互相阻塞并发性能可以接受。UPDATE语句里再带一次plan_remain 0是双保险防止锁等待期间余额被其他事务改掉。另一种做法是用乐观锁在college_plan上加version字段更新时WHERE version ?失败就重试。课设场景下考生数量不大悲观锁足够用代码也更直观。注意FOR UPDATE必须在事务里才有意义如果 autocommit 开着锁会立刻释放等于没加。2.3 录取状态流转与事务边界一个考生从「未投档」到「已投档」再到「已录取」状态流转必须和投档记录在同一个事务里。如果投档记录写成功了但考生状态没更新下次跑投档会重复处理这个考生。反过来状态更新了但记录没写就丢了投档痕迹。// Service 层的事务边界投档 状态更新 记录写入 Transactional(rollbackFor Exception.class) public void admitStudent(Long studentId, Long collegeId) { // 1. 锁定计划行 CollegePlan plan planMapper.selectForUpdate(collegeId); if (plan.getPlanRemain() 0) { throw new BizException(该校计划已满); } // 2. 扣减余额 int affected planMapper.decreaseRemain(collegeId); if (affected 0) { throw new BizException(扣减失败可能并发冲突); } // 3. 写投档记录 admissionMapper.insert(studentId, collegeId); // 4. 更新考生状态 studentMapper.updateStatus(studentId, 1); }Transactional的rollbackFor Exception.class很关键默认只回滚RuntimeException如果抛的是受检异常不会回滚投档记录和状态就会不一致。decreaseRemain返回影响行数为 0 时主动抛异常让整个事务回滚这是并发冲突下的正确姿势。3. 从源码到运行环境搭建与前后端联调3.1 后端启动Spring 配置与数据库连接拿到源码后第一步是配数据库连接。项目用的是 MySQL配置文件通常在src/main/resources/application.yml或application.properties。需要改的是数据库地址、库名、用户名和密码。spring: datasource: url: jdbc:mysql://localhost:3306/volunteer_admission?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # 连接池配置课设并发不高默认即可 hikari: maximum-pool-size: 10 minimum-idle: 2serverTimezoneAsia/Shanghai不加的话MySQL 8 会报时区错误这是最常见的启动翻车点。characterEncodingutf8保证中文考生姓名不乱码。连接池用 Spring Boot 默认的 HikariCP 就行课设场景maximum-pool-size设 10 足够设太大反而占资源。数据库建好后先执行项目里的 SQL 脚本建表和插初始数据。如果脚本里没有CREATE DATABASE语句需要手动建库mysql -u root -p -e CREATE DATABASE volunteer_admission DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p volunteer_admission schema.sql mysql -u root -p volunteer_admission data.sqlschema.sql建表data.sql插测试数据。两个脚本分开是常见做法方便重置数据时只重跑data.sql。后端启动用项目自带的 Maven Wrapper不用本地装 Maven# Windows mvnw.cmd spring-boot:run # macOS / Linux ./mvnw spring-boot:run看到Started Application in x.x seconds就说明后端起来了默认端口一般是 8080。3.2 前端构建产物与接口对接项目正文里列了一堆 CSS 文件chunk-vendors、app、chunk-xxx这些是 Vue CLI 打包后的产物命名规则。chunk-vendors放的是第三方库样式app是主应用样式chunk-开头的是按路由拆分的异步组件样式。这说明前端已经构建过dist目录里是可直接部署的静态文件。如果要改前端源码重新构建需要 Node.js 环境# 进入前端目录 cd frontend # 安装依赖国内建议配镜像 npm install --registryhttps://registry.npmmirror.com # 开发模式启动默认 8081 端口 npm run serve # 生产构建产物在 dist/ npm run build开发模式下前端跑在 8081后端跑在 8080跨域问题通过vue.config.js里的devServer.proxy解决// vue.config.js module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } }changeOrigin: true让代理请求的 Host 头变成目标地址避免后端做 Host 校验时拒绝。pathRewrite把/api前缀去掉这样前端请求/api/student/list实际打到后端/student/list。3.3 核心接口的调用顺序系统跑起来后演示流程一般是这样先登录管理员导入考生和志愿数据然后触发投档最后查录取结果。投档接口通常是一个 POST触发后台批量处理。# 登录拿 token curl -X POST http://localhost:8080/auth/login \ -H Content-Type: application/json \ -d {username:admin,password:123456} # 触发投档需要带 token curl -X POST http://localhost:8080/admission/execute \ -H Authorization: Bearer token # 查某考生录取结果 curl http://localhost:8080/admission/result/2024001 \ -H Authorization: Bearer token投档接口是幂等的还是可重复执行的取决于实现。如果每次执行都从头投需要先重置student.status和college_plan.plan_remain。常见做法是提供一个/admission/reset接口答辩演示前先重置再投结果才可复现。4. 避坑与排查课设跑不起来时先看这几条4.1 启动报时区错误现象Spring Boot 启动时抛The server time zone value ?D1ú±ê×?ê±?? is unrecognized。原因MySQL 8 的 JDBC 驱动要求显式指定时区不指定就按服务器本地时区解析中文系统下解析失败。解决连接 URL 加serverTimezoneAsia/Shanghai或者升级驱动到mysql-connector-java 8.0.23并加connectionTimeZoneLOCAL。4.2 投档结果每次不一样现象同样的数据跑两次投档录取名单不同。原因排序只按total_score排同分考生顺序不确定或者投档前没重置状态第二次是在第一次结果上继续投。解决排序加student_id做第二排序键投档前先执行重置逻辑把status和plan_remain恢复初始值。4.3 前端页面空白控制台报 404现象打开前端页面一片白F12 看到 JS/CSS 文件 404。原因vue.config.js里publicPath配的是/但部署时放在子目录下或者后端没起代理转发失败。解决部署到子目录时把publicPath改成./用相对路径确认后端 8080 端口在监听netstat -ano | findstr 8080能查到。4.4 中文乱码现象考生姓名在页面显示成??或乱码。原因数据库建库时没指定utf8mb4或者连接 URL 没加characterEncodingutf8。解决建库语句加DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci连接 URL 加characterEncodingutf8已经建好的库用ALTER DATABASE ... CHARACTER SET utf8mb4改。4.5 并发投档超录现象学校计划招 10 人结果投进去 11 个。原因没用FOR UPDATE锁计划行两个线程同时读到余额 1 都判断可投。解决投档事务里对college_plan行加SELECT ... FOR UPDATEUPDATE语句带plan_remain 0条件并检查影响行数。5. 进阶技巧用存储过程做投档回放与结果校验课设答辩时老师最爱问的一句话是「你怎么证明投档结果是对的」。光靠页面展示说服力不够最好能拿出一套可回放的验证方法。我一般会写一个存储过程把投档过程的关键中间状态记到日志表里跑完之后用 SQL 直接校验规则是否被违反。先建一张投档日志表CREATE TABLE admission_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, student_no VARCHAR(20), total_score INT, college_id BIGINT, volunteer_order TINYINT, plan_before INT, plan_after INT, log_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;然后在投档的 Service 里每次扣减余额前后各记一条日志。跑完投档后用下面这条 SQL 校验「分数优先」有没有被违反——如果存在一个分数更低的考生被录取而分数更高的考生落榜且该学校还有余额就说明排序逻辑有问题-- 校验是否存在低分录取而高分落榜的异常 SELECT a.student_no AS low_score_admitted, b.student_no AS high_score_rejected, a.total_score, b.total_score FROM admission_record a JOIN student b ON b.status 0 -- 未投档的高分考生 WHERE a.total_score b.total_score AND EXISTS ( SELECT 1 FROM college_plan cp WHERE cp.college_id a.college_id AND cp.plan_remain 0 );正常情况下这条查询应该返回空集。如果返回了记录说明投档顺序错了或者计划余额扣减有并发问题。这个校验思路比单纯看页面结果靠谱得多答辩时把这条 SQL 跑给老师看比说一百句「我用了事务」都有用。再进一步可以用存储过程模拟「回放」把admission_log按log_time排序逐条重放plan_before → plan_after的变化检查每一步的plan_after plan_before - 1且plan_after 0。任何一步不满足就定位到具体是哪个考生、哪个学校出的问题。-- 回放校验检查每次扣减是否合法 SELECT id, student_no, college_id, plan_before, plan_after FROM admission_log WHERE plan_after ! plan_before - 1 OR plan_after 0;这条查询同样应该返回空集。两条校验 SQL 加上日志表就构成了一套最小可用的投档正确性验证方案。我后来做任何涉及余额扣减的系统都会先建日志表再写业务代码——出问题时能回放比事后猜强太多。从那以后我每次做这类课设或项目都强制先把日志和校验 SQL 写好再动主逻辑这个习惯帮我省了无数次返工。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。