ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Java Swing + MySQL 选课管理系统实战:从环境搭建到事务处理

Java Swing + MySQL 选课管理系统实战:从环境搭建到事务处理 简介这份资源是面向Java初学者与在校学生的选课管理系统完整源码包采用Java Swing做桌面界面、MySQL做数据存储适合用作课程设计、期末大作业或自学练手项目。压缩包共15个文件以14个java源文件和1个sql数据库脚本为主整体仅19KB轻量易部署导入数据库后即可运行。系统涵盖学生、课程、选课等核心模块代码附有注释新手也能看懂整体结构与业务逻辑。目前已有162人学习下载说明其作为入门级实战项目具有一定参考价值。读者可获得一套可直接运行的选课管理方案包括建库脚本、界面代码与增删改查实现便于快速理解Swing事件处理、JDBC连接与表结构设计也能在此基础上二次修改完成符合要求的课程作业。1. 从零跑通 Java Swing MySQL 选课管理系统小白也能上手的桌面端方案很多同学做 Java 课程设计时第一反应是去网上找一份“学生选课管理系统”源码结果下载下来要么跑不起来要么数据库连不上要么界面一片空白。这个标题指向的其实是一套非常经典的组合用 Java Swing 做桌面客户端用 MySQL 存数据实现学生选课、退课、课程管理、成绩录入这些核心功能。它适合正在做课程设计、毕业设计或者想通过一个完整项目把 Java 基础、JDBC、Swing 界面串起来的新手。你不需要先精通 Spring 或前端框架只要会基本的 Java 语法就能跟着把环境搭起来、把表建好、把源码跑通。这一章先把这套系统到底包含什么、为什么选 Swing 而不是 Web、以及小白最容易卡在哪讲清楚后面再一步步动手。2. 环境准备与数据库设计把 MySQL 和 JDK 先装明白2.1 JDK 安装与环境变量配置的实操步骤选课管理系统源码通常基于 JDK 8 或 JDK 11 编写因为 Swing 和 JDBC 在这两个版本上最稳定。如果你用的是最新版 JDK可能会遇到javax.swing包被移除或模块化限制的问题所以建议先装 JDK 8 或 JDK 11。安装过程本身不复杂关键是环境变量要配对。Windows 下配置JAVA_HOME和Path的常见做法是# 假设 JDK 安装在 C:\Program Files\Java\jdk1.8.0_301 # 新建系统变量 JAVA_HOME JAVA_HOME C:\Program Files\Java\jdk1.8.0_301 # 编辑 Path添加以下两条 %JAVA_HOME%\bin %JAVA_HOME%\jre\bin配置完成后打开新的命令行窗口执行java -version和javac -version如果都能正确输出版本号说明环境变量生效。这里有个血泪经验很多人改完 Path 后没有关掉原来的 cmd 窗口导致一直提示“不是内部或外部命令”其实只是旧窗口没重新加载环境变量。提示如果你同时装了多个 JDKjava -version显示的可能不是你刚配的那个检查 Path 里%JAVA_HOME%\bin是否排在其他 Java 路径前面。2.2 MySQL 安装与选课数据库表结构设计MySQL 推荐用 5.7 或 8.0 版本安装时记住 root 密码字符集选utf8mb4。安装完成后用 MySQL Workbench 或者命令行登录先创建一个数据库比如course_selection。选课管理系统的核心表一般包括学生表、教师表、课程表、选课记录表。下面是一份可以直接抄的建表 SQL-- 创建数据库 CREATE DATABASE course_selection DEFAULT CHARACTER SET utf8mb4; USE course_selection; -- 学生表 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL DEFAULT 123456, major VARCHAR(50), grade VARCHAR(20) ); -- 教师表 CREATE TABLE teacher ( id INT PRIMARY KEY AUTO_INCREMENT, teacher_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL DEFAULT 123456, title VARCHAR(30) ); -- 课程表 CREATE TABLE course ( id INT PRIMARY KEY AUTO_INCREMENT, course_no VARCHAR(20) NOT NULL UNIQUE, course_name VARCHAR(100) NOT NULL, teacher_id INT, credit INT DEFAULT 2, capacity INT DEFAULT 50, selected_count INT DEFAULT 0, semester VARCHAR(30), FOREIGN KEY (teacher_id) REFERENCES teacher(id) ); -- 选课记录表 CREATE TABLE selection ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, select_time DATETIME DEFAULT CURRENT_TIMESTAMP, score INT DEFAULT NULL, UNIQUE KEY uk_student_course (student_id, course_id), FOREIGN KEY (student_id) REFERENCES student(id), FOREIGN KEY (course_id) REFERENCES course(id) );这段 SQL 里几个关键点student_no和course_no加了唯一约束防止重复学号或课程号selection表用UNIQUE KEY保证同一个学生不能重复选同一门课selected_count用来记录已选人数选课时要判断是否超过capacity。这些约束在代码里也要做校验但数据库层面先兜底能避免很多脏数据。注意MySQL 8.0 默认认证插件是caching_sha2_password老版本 JDBC 驱动可能连不上。如果报错Unable to load authentication plugin要么升级mysql-connector-java到 8.0 以上要么把用户认证方式改成mysql_native_password。3. 源码结构拆解与 JDBC 连接让 Swing 界面真正读到数据3.1 选课管理系统源码的典型包结构一份标准的 Java Swing 选课管理系统源码通常按功能分层包名可能略有差异但大体结构如下src/ ├── com/ │ └── course/ │ ├── dao/ # 数据库操作层 │ │ ├── StudentDao.java │ │ ├── CourseDao.java │ │ └── SelectionDao.java │ ├── model/ # 实体类 │ │ ├── Student.java │ │ ├── Course.java │ │ └── Selection.java │ ├── ui/ # Swing 界面 │ │ ├── LoginFrame.java │ │ ├── StudentMainFrame.java │ │ └── TeacherMainFrame.java │ ├── util/ # 工具类 │ │ └── DBUtil.java │ └── Main.java # 程序入口 └── lib/ └── mysql-connector-java-8.0.xx.jar拿到源码后先看lib目录下有没有 JDBC 驱动 jar 包。如果没有去 MySQL 官网下载mysql-connector-java版本要和你的 MySQL 版本匹配。然后在 IDE 里把这个 jar 加到项目的 Build Path 或 Libraries 中。很多小白跑不起来就是因为只导入了源码没导入驱动。3.2 DBUtil 工具类与 JDBC 连接参数怎么改DBUtil是整个系统连接数据库的入口通常长这样package com.course.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { // 数据库连接参数需要根据你本机环境修改 private static final String URL jdbc:mysql://localhost:3306/course_selection?useSSLfalseserverTimezoneUTCcharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 你的MySQL密码; static { try { // 加载 MySQL 驱动 Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn) { if (conn ! null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }这里有几个参数必须改URL里的course_selection要和你实际创建的数据库名一致USER和PASSWORD换成你本机的 MySQL 账号密码serverTimezoneUTC是为了解决 MySQL 8.0 时区报错如果你用的是 MySQL 5.7可以不加。Class.forName里驱动类名MySQL 8.0 用com.mysql.cj.jdbc.Driver5.7 用com.mysql.jdbc.Driver写错了会直接抛ClassNotFoundException。提示如果连接时报Public Key Retrieval is not allowed在 URL 后面加上allowPublicKeyRetrievaltrue。3.3 学生选课与退课的核心 DAO 方法选课逻辑不能只写一条INSERT还要判断课程容量、是否已选、然后更新已选人数。下面是一个典型的选课方法public boolean selectCourse(int studentId, int courseId) { String checkSql SELECT capacity, selected_count FROM course WHERE id ?; String checkSelected SELECT COUNT(*) FROM selection WHERE student_id ? AND course_id ?; String insertSql INSERT INTO selection (student_id, course_id) VALUES (?, ?); String updateSql UPDATE course SET selected_count selected_count 1 WHERE id ?; try (Connection conn DBUtil.getConnection()) { conn.setAutoCommit(false); // 开启事务 // 1. 检查是否已经选过 try (PreparedStatement ps conn.prepareStatement(checkSelected)) { ps.setInt(1, studentId); ps.setInt(2, courseId); ResultSet rs ps.executeQuery(); if (rs.next() rs.getInt(1) 0) { conn.rollback(); return false; // 已选过 } } // 2. 检查容量 try (PreparedStatement ps conn.prepareStatement(checkSql)) { ps.setInt(1, courseId); ResultSet rs ps.executeQuery(); if (rs.next()) { int capacity rs.getInt(capacity); int selected rs.getInt(selected_count); if (selected capacity) { conn.rollback(); return false; // 已满 } } } // 3. 插入选课记录 try (PreparedStatement ps conn.prepareStatement(insertSql)) { ps.setInt(1, studentId); ps.setInt(2, courseId); ps.executeUpdate(); } // 4. 更新已选人数 try (PreparedStatement ps conn.prepareStatement(updateSql)) { ps.setInt(1, courseId); ps.executeUpdate(); } conn.commit(); return true; } catch (SQLException e) { e.printStackTrace(); return false; } }这段代码的关键在于事务检查容量、插入记录、更新人数必须在一个事务里否则并发选课时会出现“超选”。setAutoCommit(false)开启事务任何一步失败都rollback。退课方法类似先删除selection记录再把selected_count减一同样要放在事务里。注意Swing 是单线程界面工具包数据库操作不要直接放在按钮的actionPerformed里否则界面会卡死。常见做法是用SwingWorker在后台线程执行 DAO 方法完成后在done()里更新表格。4. Swing 界面与业务逻辑对接登录、选课、成绩录入怎么串起来4.1 登录窗口如何区分学生和教师角色登录界面通常用一个JFrame放用户名、密码、角色下拉框。点击登录后根据角色去查student表或teacher表。核心代码片段String role (String) roleBox.getSelectedItem(); String sql SELECT id, name FROM (学生.equals(role) ? student : teacher) WHERE student_no ? AND password ?; // 如果是教师表字段名要改成 teacher_no这里有个容易翻车的地方学生表和教师表的学号/工号字段名不一样拼 SQL 时要么统一字段名要么分开写两个查询。我一般建议分开写可读性更好也不容易出注入问题。登录成功后把用户 id 和姓名存到一个全局对象里后续选课、查成绩都要用。4.2 用 JTable 展示可选课程和已选课程选课主界面一般用两个JTable上面是可选课程列表下面是已选课程列表。JTable的数据模型用DefaultTableModel从 DAO 查出ListCourse后遍历填充。DefaultTableModel model (DefaultTableModel) courseTable.getModel(); model.setRowCount(0); // 清空旧数据 ListCourse courses courseDao.findAllAvailable(); for (Course c : courses) { model.addRow(new Object[]{c.getId(), c.getCourseNo(), c.getCourseName(), c.getTeacherName(), c.getCredit(), c.getCapacity() - c.getSelectedCount()}); }刷新表格时一定要先setRowCount(0)否则每次查询都会追加表格越来越长。选课按钮触发后调用selectCourse成功则弹JOptionPane.showMessageDialog提示并刷新两个表格。4.3 教师端成绩录入与学生成绩查询教师登录后界面应该只显示自己所授课程。查询 SQL 加一个WHERE teacher_id ?。选中某门课后表格列出选了这门课的学生最后一列可编辑用于录入成绩。JTable默认不可编辑需要自定义isCellEditable或者用DefaultTableModel重写。成绩保存时更新selection表的score字段UPDATE selection SET score ? WHERE student_id ? AND course_id ?;学生端查询成绩则用SELECT course_name, score FROM selection s JOIN course c ON s.course_id c.id WHERE s.student_id ?。这里要注意成绩为NULL表示未录入界面上显示“未录入”而不是 0。提示Swing 的JTable如果直接放JScrollPane里表头不会显示必须new JScrollPane(table)这样包一层。5. 避坑与排查小白跑选课系统最常见的 5 个翻车现场5.1 报错 Access denied for user rootlocalhost现象程序启动后连数据库直接抛SQLException: Access denied for user rootlocalhost (using password: YES)。原因DBUtil里的密码和本机 MySQL 实际密码不一致或者 MySQL 根本没启动。解决先用命令行mysql -u root -p试一下能不能登录。如果命令行能登录说明密码对检查DBUtil里有没有多余空格如果命令行也登不上说明密码错了需要重置 MySQL 密码。另外确认 MySQL 服务是否在运行Windows 下看服务列表里MySQL80或MySQL57是否已启动。5.2 中文乱码数据库里存进去变成问号现象学生姓名、课程名插入后变成???或者查询出来是乱码。原因数据库、表、连接 URL 三处字符集不统一。解决建库时用utf8mb4连接 URL 加characterEncodingutf8MySQL 配置文件my.ini里character-set-serverutf8mb4。如果已经建了表用ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4;改一下。Swing 界面本身一般不会乱码乱码基本都出在数据库这一层。5.3 选课按钮点下去没反应也不报错现象点击选课按钮界面没提示数据库也没新增记录。原因最常见的是按钮事件没绑定或者ActionListener里异常被catch后只打印了堆栈而控制台被关了没看到。解决先看 IDE 控制台有没有红色报错。如果没有在actionPerformed第一行加System.out.println(按钮被点击);确认事件触发。如果触发了但没进 DAO检查studentId是不是 0 或 null。我遇到过因为登录后没把用户 id 存到全局变量选课时传了个默认值 0导致外键约束失败但异常被吞了。5.4 表格数据重复叠加越刷新越多现象每次点“刷新”按钮JTable里就多出一倍数据。原因DefaultTableModel没有清空直接addRow追加。解决在填充数据前调用model.setRowCount(0)。如果是自定义AbstractTableModel需要重新fireTableDataChanged()。这个坑几乎每个新手都会踩一次记住“先清后加”。5.5 打包成 jar 后运行提示找不到 JDBC 驱动现象在 IDE 里跑得好好的导出成可执行 jar 后双击运行报ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因JDBC 驱动 jar 没有一起打包进去或者MANIFEST.MF里没写Class-Path。解决用java -jar your.jar在命令行运行看完整报错。如果确实缺驱动要么把mysql-connector-java.jar放到和你的 jar 同一目录并在MANIFEST.MF里加Class-Path: mysql-connector-java-8.0.xx.jar要么用 Maven 的shade插件打成 fat jar。新手建议先用命令行方式跑确认没问题再研究打包。6. 进阶技巧用 SwingWorker 解决界面卡顿与事务回滚验证选课系统做到后面最影响体验的不是功能多少而是点一下卡三秒。Swing 的事件分发线程EDT一旦被数据库查询阻塞整个界面就会假死。我一般会强制自己把所有 DAO 调用都放进SwingWorker哪怕只是查一条记录。new SwingWorkerBoolean, Void() { Override protected Boolean doInBackground() throws Exception { // 后台线程执行选课不阻塞界面 return selectionDao.selectCourse(studentId, courseId); } Override protected void done() { try { boolean success get(); if (success) { JOptionPane.showMessageDialog(null, 选课成功); refreshTables(); // 回到 EDT 刷新界面 } else { JOptionPane.showMessageDialog(null, 选课失败已选过或课程已满); } } catch (Exception e) { e.printStackTrace(); } } }.execute();doInBackground里做耗时操作done里更新 UI这是 Swing 的规矩。get()会抛出ExecutionException如果后台有异常这里能捕获到不会无声无息地吞掉。另一个进阶点是验证事务回滚。你可以故意把updateSql写错表名然后选一门课观察selection表里有没有插入记录。如果事务生效插入应该被回滚selection表不会多数据。这个验证方法比看代码可靠得多我每次改完选课逻辑都会跑一遍。验证项操作预期结果重复选课同一学生选同一课程两次第二次提示失败selection 表只有一条记录容量已满把 capacity 改成 1两个学生选同一课第二个学生失败selected_count 保持 1事务回滚故意让更新人数 SQL 报错selection 表无新增记录中文存储插入带中文的课程名数据库和界面都显示正常最后说个我自己的习惯每次改完 DAO 方法先不急着开界面写一个main方法直接调 DAO用System.out.println看返回值。界面层的问题和数据库层的问题分开排查能省掉大量“到底是哪一层错了”的纠结。这套选课管理系统虽然简单但把 JDBC 事务、Swing 线程模型、数据库约束这几块吃透后面做任何 Java 桌面项目都不会慌。希望帮到你。本文还有配套的精品资源点击获取
返回列表