高校学生选课系统是教务管理中的核心模块,我参与开发的这套系统采用Java+Vue技术栈实现。系统上线后日均处理3万+选课请求,峰值并发达到2000+,稳定运行3个学期无重大故障。相比传统选课方式,系统将选课成功率从68%提升到92%,退换课处理时间从3个工作日缩短至实时生效。
这个系统最让我自豪的是解决了"选课难"这个老大难问题。通过分布式锁和课程余量预扣机制,在2023年春季学期成功应对了开课首日12万次的选课冲击。后台采用Spring Cloud微服务架构,前端使用Vue3+Element Plus,数据库选用MySQL集群配合Redis缓存。
系统采用前后端分离架构,这是我经过多次技术选型对比后的决定。后端使用Spring Boot 2.7 + MyBatis Plus构建微服务,通过Nginx实现负载均衡。前端采用Vue3组合式API开发,使用Vite构建工具大幅提升编译速度。
技术选型时重点考虑了几个因素:
课程数据采用分库分表策略,主库存储课程基础信息,分库处理选课记录。关键表结构设计:
sql复制CREATE TABLE `course` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '课程ID',
`course_code` varchar(20) NOT NULL COMMENT '课程编号',
`name` varchar(100) NOT NULL COMMENT '课程名称',
`credit` tinyint NOT NULL COMMENT '学分',
`capacity` int NOT NULL DEFAULT '0' COMMENT '容量',
`selected` int NOT NULL DEFAULT '0' COMMENT '已选人数',
`teacher_id` bigint NOT NULL COMMENT '教师ID',
`time_slot` json DEFAULT NULL COMMENT '时间安排',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`course_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意:
高并发选课是系统最大挑战,我们实现了三级防护:
关键Java代码片段:
java复制public boolean selectCourse(Long studentId, Long courseId) {
// 获取分布式锁
RLock lock = redissonClient.getFairLock("lock:course:" + courseId);
try {
lock.lock(5, TimeUnit.SECONDS);
Course course = courseMapper.selectById(courseId);
if (course.getSelected() >= course.getCapacity()) {
return false;
}
// 使用乐观锁更新
int updated = courseMapper.updateSelected(courseId, course.getVersion());
return updated > 0;
} finally {
lock.unlock();
}
}
采用位运算实现高效时间冲突检测:
java复制public boolean hasTimeConflict(BitSet existing, BitSet newCourse) {
BitSet clone = (BitSet) existing.clone();
clone.and(newCourse);
return !clone.isEmpty();
}
基于Vue3的自定义课表组件实现:
vue复制<template>
<div class="timetable">
<div v-for="(day, i) in weekDays" :key="i" class="day-column">
<div class="time-slot"
v-for="slot in timeSlots"
:class="{'occupied': isOccupied(day, slot)}"
@click="handleSlotClick(day, slot)">
{{ getCourseName(day, slot) }}
</div>
</div>
</div>
</template>
优化技巧:
实测优化效果:
生产环境采用3节点集群:
Nginx关键配置:
nginx复制upstream backend {
server 192.168.1.101:8080 weight=3;
server 192.168.1.102:8080 weight=2;
server 192.168.1.103:8080 weight=2;
keepalive 32;
}
server {
listen 443 ssl;
server_name course.university.edu;
ssl_certificate /path/to/cert.pem;
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
搭建的监控体系包括:
重点监控指标:
在退课-选课原子操作场景下,最初使用本地事务导致数据不一致。最终解决方案:
课程余量更新后缓存未及时失效,导致超选。解决方案:
java复制@CacheEvict(value = "courses", key = "#courseId")
public void updateCourseCapacity(Long courseId, int newCapacity) {
// 先更新数据库
courseMapper.updateCapacity(courseId, newCapacity);
// 延迟双删
redisTemplate.delete("course:" + courseId);
executor.schedule(() ->
redisTemplate.delete("course:" + courseId),
1, TimeUnit.SECONDS);
}
实现推荐系统的伪代码:
python复制def recommend_courses(student_id):
history = get_history_courses(student_id)
similar_students = find_similar_users(history)
recommendations = aggregate_courses(similar_students)
return filter_available(recommendations)
这个项目让我深刻体会到,一个好的选课系统不仅要技术过硬,更要理解教育场景的特殊需求。比如处理重修生选课优先级问题时,就需要在技术方案中融入教务规则。下次如果再开发类似系统,我会更早介入需求分析阶段,把业务规则理解透彻再开始编码。