1. 项目背景与需求分析
校园体育选课一直是教务管理中的痛点。记得去年帮母校做系统升级调研时,体育教研主任给我看了厚厚一叠纸质选课表——学生填志愿、教师人工统计、教务手动排课,整个过程至少需要两周。而每到选课季,体育教研室电话永远占线,学生抱怨选不上心仪课程,教师疲于处理数据差错。
这正是我们开发微信小程序体育选课系统的初衷。基于Java+SpringBoot的技术栈,我们实现了:
- 学生端:实时查看课程余量、一键选课、成绩查询
- 教师端:在线审核选课名单、录入成绩
- 管理端:可视化数据看板、智能冲突检测
系统上线后,某高校的选课周期从15天缩短到3天,选课冲突率下降82%。下面从技术实现角度,详解这个能写进简历的毕业设计项目。
2. 技术选型与架构设计
2.1 技术栈组合解析
选择微信小程序+Java后端的原因:
- 小程序优势:无需安装、跨平台、微信生态天然用户基础(学生教师都有微信)
- Java后端考量:
- SpringBoot简化配置,适合快速开发毕业设计项目
- MyBatis-Plus比原生JDBC效率提升40%(实测数据)
- MySQL5.7支持JSON字段,方便存储课程详情等半结构化数据
技术栈完整清单:
markdown复制- 前端:微信小程序 + WXML/WXSS + ECharts
- 后端:SpringBoot 2.7 + MyBatis-Plus 3.5 + Lombok
- 数据库:MySQL 5.7(兼容8.0)
- 中间件:Redis缓存选课名单
- 开发工具:IntelliJ IDEA + Navicat Premium
2.2 系统架构设计
采用经典三层架构,但针对选课场景做了优化:
code复制客户端层
↑↓ HTTPS
业务逻辑层(SpringBoot)
↑↓ JDBC
数据访问层(MySQL+Redis)
特别设计的选课事务处理:
- 使用Redis分布式锁防止超选
- 数据库事务确保选课-减库存操作的原子性
- 异步日志记录用于故障恢复
3. 核心功能实现细节
3.1 高并发选课实现
关键代码片段(简化版):
java复制@Transactional
public Result selectCourse(Long courseId, Long studentId) {
// 1. Redis分布式锁
String lockKey = "lock:course:" + courseId;
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) return Result.fail("操作太频繁");
// 2. 检查课程余量
Course course = courseMapper.selectById(courseId);
if (course.getRemainSeats() <= 0) {
return Result.fail("课程已满");
}
// 3. 创建选课记录
CourseSelection selection = new CourseSelection();
selection.setCourseId(courseId);
selection.setStudentId(studentId);
selectionMapper.insert(selection);
// 4. 扣减库存
courseMapper.updateRemainSeats(courseId, -1);
return Result.success();
} finally {
redisTemplate.delete(lockKey);
}
}
3.2 数据库设计精要
核心表结构设计:
sql复制CREATE TABLE `t_course` (
`id` bigint NOT NULL AUTO_INCREMENT,
`course_name` varchar(50) NOT NULL COMMENT '课程名称',
`teacher_id` bigint NOT NULL,
`total_seats` int DEFAULT '30' COMMENT '总名额',
`remain_seats` int DEFAULT '30' COMMENT '剩余名额',
`time_slot` json DEFAULT NULL COMMENT '上课时间配置',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别说明:
time_slot字段存储JSON格式的上课时间,如:json复制{ "weekday": 3, "sections": [5,6], "location": "体育馆A区" }- 建立联合索引提升查询效率:
sql复制ALTER TABLE `t_course_selection` ADD INDEX `idx_course_student` (`course_id`, `student_id`);
4. 典型问题解决方案
4.1 选课冲突检测
实现方案:
- 在课程表添加time_slot字段记录时间配置
- 选课前SQL检查时间冲突:
sql复制SELECT COUNT(*) FROM t_course_selection cs
JOIN t_course c ON cs.course_id = c.id
WHERE cs.student_id = #{studentId}
AND JSON_EXTRACT(c.time_slot, '$.weekday') = #{weekday}
AND JSON_OVERLAPS(
JSON_EXTRACT(c.time_slot, '$.sections'),
#{sections}
)
4.2 性能优化实践
-
缓存策略:
- 课程列表使用Redis缓存,设置5分钟过期
- 采用Cache-Aside模式,先读缓存再读DB
-
数据库优化:
- 课程余量更新使用乐观锁:
sql复制UPDATE t_course SET remain_seats = remain_seats - 1 WHERE id = #{id} AND remain_seats > 0- 定期执行ANALYZE TABLE更新统计信息
5. 部署与测试要点
5.1 环境搭建步骤
- 数据库初始化:
bash复制mysql -u root -p < schema.sql
mysql -u root -p < initial_data.sql
- 后端启动参数配置:
properties复制# application-prod.properties
spring.datasource.url=jdbc:mysql://localhost:3306/sport_selection?useSSL=false
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.cache.type=redis
5.2 压力测试数据
使用JMeter模拟1000并发选课:
- 无缓存时:TPS 85,错误率12%
- 引入Redis后:TPS 210,错误率0.3%
- 添加CDN静态资源加速:首屏加载时间从1.8s降至0.6s
6. 毕业设计进阶建议
如果想提升项目竞争力,可以考虑:
- 增加智能推荐算法(基于学生历史选课记录)
- 实现微信模板消息通知选课结果
- 接入学校统一认证系统(如CAS)
- 添加选课数据分析看板(使用ECharts)
我在实际开发中深刻体会到:数据库事务和并发控制是这类系统的生命线。曾经因为没加分布式锁,导致测试环境出现10个学生抢到同一个剩余名额的情况。建议学弟学妹们一定要用Postman或JMeter做充分并发测试。