
1. 项目概述前后端分离选课系统的技术架构这个学生选课系统采用了典型的前后端分离架构后端使用SpringBoot框架提供RESTful API接口前端通过Vue.js构建用户界面数据持久层采用MyBatis操作MySQL数据库。这种架构模式在当前企业级应用开发中已经成为主流选择特别适合需要快速迭代的校园信息化项目。我在实际开发中发现选课系统有几个典型的技术痛点高并发选课时的性能瓶颈、多条件组合查询的响应速度、前后端数据格式的规范统一。这套技术栈的组合恰好能针对性解决这些问题——SpringBoot的内置Tomcat容器和线程池机制能处理突发流量MyBatis的动态SQL支持复杂查询条件拼接而Vue的axios拦截器可以统一处理API响应。2. 技术栈选型与核心组件解析2.1 SpringBoot后端框架设计选型SpringBoot而非传统SSM框架的主要考虑是简化配置。实际开发中通过starter依赖快速集成了spring-boot-starter-webWeb MVCspring-boot-starter-aop事务管理mybatis-spring-boot-starterMybatis集成druid-spring-boot-starter数据库连接池特别值得分享的是事务配置技巧。在选课业务中我们需要保证选课-扣减名额-生成课表的原子性操作。通过Transactional注解配合隔离级别配置可以这样实现Transactional(isolation Isolation.READ_COMMITTED, propagation Propagation.REQUIRED) public CourseSelectionResult selectCourse(Long studentId, Long courseId) { // 业务逻辑 }2.2 Vue前端工程化实践前端采用Vue CLI创建的工程结构通过以下关键配置提升开发效率使用vue-router实现前端路由鉴权通过vuex管理全局状态如用户登录信息配置axios实例统一处理API请求/响应一个典型的API请求拦截器配置示例// src/utils/request.js const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 5000 }) service.interceptors.request.use(config { if (store.getters.token) { config.headers[Authorization] Bearer getToken() } return config })2.3 MyBatis数据持久层优化针对选课系统的高频查询场景我们在MyBatis层做了这些优化二级缓存配置在mybatis-config.xml中启用Ehcache动态SQL编写使用 标签避免空条件导致语法错误结果集映射通过 定义复杂的DTO映射关系典型的多条件查询动态SQL示例select idselectAvailableCourses resultMapCourseDTO SELECT * FROM courses where if testcourseName ! null AND name LIKE CONCAT(%,#{courseName},%) /if if testteacherId ! null AND teacher_id #{teacherId} /if if testremainingQuota 0 AND remaining_quota 0 /if /where ORDER BY create_time DESC /select3. 数据库设计与性能考量3.1 核心表结构设计主要包含以下表及其关系students学生信息teachers教师信息courses课程主表course_sections课程分班表selections选课记录表schedules个人课表特别注意课程余量字段的设计方案。最初我们采用实时计算COUNT(selections)但在高并发下出现性能问题。后来改为在courses表维护remaining_quota字段通过触发器自动更新CREATE TRIGGER update_quota AFTER INSERT ON selections FOR EACH ROW BEGIN UPDATE courses SET remaining_quota remaining_quota - 1 WHERE id (SELECT course_id FROM course_sections WHERE id NEW.section_id); END;3.2 索引优化策略根据实际查询场景我们建立了这些关键索引课程表name字段前缀索引课程名搜索选课记录联合索引(student_id, section_id)防止重复选课教师表department_id索引按院系筛选使用EXPLAIN分析慢查询时发现课程分页查询缺少排序字段索引。添加后的性能对比查询条件无索引耗时有索引耗时前10条记录320ms45ms第100页记录2800ms150ms4. 系统部署实战方案4.1 后端部署要点SpringBoot应用推荐两种部署方式打包为可执行JAR通过nohup后台运行nohup java -jar selection-system.jar --server.port8080 app.log 21 构建Docker镜像适合集群部署FROM openjdk:8-jdk-alpine VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT [java,-jar,/app.jar]4.2 前端部署注意事项Vue项目构建时需要特别注意配置生产环境API地址在.env.production设置VUE_APP_BASE_API路由history模式需要Nginx额外配置location / { try_files $uri $uri/ /index.html; }静态资源CDN加速修改vue.config.js中的publicPath4.3 数据库部署建议MySQL部署时的关键参数调整针对选课场景[mysqld] innodb_buffer_pool_size 2G # 缓存池大小 innodb_log_file_size 256M # 日志文件大小 max_connections 500 # 最大连接数 transaction_isolation READ-COMMITTED5. 典型问题排查手册5.1 跨域问题解决方案开发环境常见跨域问题可通过以下方式解决后端配置CORS推荐方案Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(*) .maxAge(3600); } }前端代理配置vue.config.jsdevServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }5.2 选课并发冲突处理我们测试时发现当多个学生同时选同一门课时可能出现超卖情况。最终采用两种方案结合数据库乐观锁UPDATE courses SET remaining_quota remaining_quota - 1 WHERE id ? AND remaining_quota 0Redis分布式锁应对集群部署public boolean tryLock(String key, long expire) { return redisTemplate.opsForValue() .setIfAbsent(key, 1, expire, TimeUnit.SECONDS); }5.3 性能监控方案线上系统推荐集成SpringBoot Actuator监控添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency配置开放端点application.ymlmanagement: endpoints: web: exposure: include: health,info,metrics自定义业务指标监控Service public class CourseMetrics { private final Counter selectionCounter; public CourseMetrics(MeterRegistry registry) { selectionCounter registry.counter(course.selection.count); } public void recordSelection() { selectionCounter.increment(); } }6. 项目扩展方向建议基于现有系统可以考虑以下增强功能微信小程序端使用uni-app重构前端覆盖移动场景选课结果分析集成Python计算引擎进行选课数据挖掘微服务改造将课程管理、选课操作拆分为独立服务实时通知通过WebSocket推送选课状态变更在架构演进过程中建议先完善监控体系再实施改造。我们团队在拆分微服务时曾因缺乏链路追踪导致问题定位困难后来通过集成SkyWalking解决了这个问题。