Java Swing + MySQL 学生管理系统:JDBC 连接、增删改查与避坑指南

发布时间:2026/10/8 18:32:59
Java Swing + MySQL 学生管理系统:JDBC 连接、增删改查与避坑指南
简介这是一个基于Java Swing和MySQL数据库开发的学生信息管理系统完整项目主要面向Java初学者、高校在校生以及需要完成课程设计或毕业设计的开发者。系统实现了管理员登录、学生信息增加、删除、修改、查询及列表展示等核心功能代码结构清晰适合直接用IDE导入运行也可作为学习JDBC数据库操作、Swing界面编程的参考项目。压缩包内共有48个文件包括15个Java源代码文件、22个编译后的class文件、数据库初始化SQL脚本、系统运行所需的jar依赖包以及4张界面效果截图整体大小仅1.04MB目录划分明确便于快速定位源码、配置与依赖。目前该项目已有2292人学习具有不错的参考热度。项目附带演示链接和作者支持服务提供环境安装、调试答疑及小需求修改能帮助使用者在部署和运行环节少走弯路更专注于理解业务逻辑与界面实现。1. 先把话说明白这套 Java Swing MySQL 学生管理系统到底解决什么问题做课程设计最怕的不是不会写代码而是写完增删改查才发现交不上去界面排版稀烂、数据库连不上、老师一打开就报错。这套学生信息管理系统正好卡在每个 Java 学习者都会撞上的那个点上——用 Java Swing 做桌面界面用 MySQL 存数据中间靠 JDBC 串起来数据库脚本、源码、依赖包全都给你配好。你拿到手之后主干功能是完整能跑的不需要从零搭骨架要做的只是把环境配好、把连接参数改对然后在这个基础上做你自己的改动。适合正在做课程设计、毕设或者刚学完 Java 基础想找个完整项目看整体结构的同学哪怕你只会照着抄也能靠它把「增删改查 登录 列表展示」这套标准流程完整走通。2. 解压后先别急着写代码从 bin、lib 到 jgoodies-forms 的工程结构2.1 资源包里的每个文件是干什么的学生信息管理系统.rar 解开之后里面是一个标准的 Eclipse 老工程目录长这样stu_manage/ ├── .classpath # Eclipse 工程类路径配置 ├── .project # Eclipse 工程描述文件 ├── .settings/ # Eclipse 编译器/编码配置 ├── bin/ # 编译输出目录可删 ├── images/ # 界面图标、背景图资源 ├── lib/ # 外部依赖 jar 包 │ ├── jgoodies-forms-1.8.0.jar │ └── jgoodies-forms-1.8.0-sources.jar ├── src/ # 全部 Java 源码 └── db_stu.sql # MySQL 建库建表脚本先明确哪些能碰、哪些不能碰。.classpath、.project、.settings是 Eclipse 的工程元数据你用 IDEA 打开的时候它不参与编译但别手贱删掉因为保留着它们你还能用 Eclipse 直接导入。bin/是编译产物删了也无所谓IDE 会重新生成。images/是给界面用的图标和背景图窗口里的按钮、Logo、启动欢迎图都指向这个目录删了会报找不到图片资源所以原样保留就行。lib/里那两个 jar 才是关键。jgoodies-forms-1.8.0.jar 是一个表单布局库作者用它来把登录框、输入框、按钮这些控件按行列对齐比 Swing 自带的 GridBagLayout 好写得多。旁边还放了一个jgoodies-forms-1.8.0-sources.jar这是同版本的源码包你在 IDEA 里点进 FormLayout 类的时候能直接看到官方实现排查布局问题会省很多事——这个细节不是每个项目都会给你配的说明作者确实考虑过调试场景。这两个 jar 必须同时加进项目依赖缺了主包直接编译不过。2.2 用 Eclipse 导入还是 IDEA 导入这套资源最省事的打开方式是 Eclipse。菜单栏 File → Import → General → Existing Projects into Workspace选择解压后的stu_manage目录Finish 之后直接 F11 就能跑。因为.project文件里已经写好了项目名和构建路径Eclipse 会自己把lib/下的 jar 配进去不需要你再手动 add library。如果你用的是 IDEA就别选 Open 了应该选 File → New → Project from Existing Sources然后选中stu_manage目录IDEA 会识别出这是一个 Eclipse 项目一路 Next 到 SDK 选择界面选你本机的 JDK 1.8。导入完成后打开 Project Structure → Libraries确认jgoodies-forms-1.8.0.jar已经在依赖列表里没有就手动加上。第一次启动前必须把数据库准备好。当初作者打包测试时用的是 MySQL 5.7 和 8.0 都能跑前提是lib/里你有对应的 JDBC 驱动。这套资源里没有单独放mysql-connector-java的驱动 jar所以这是你唯一需要自己补的依赖——别疑惑作者默认你会装。驱动版本和 MySQL 版本必须匹配MySQL 5.7 用mysql-connector-java-5.1.49.jarMySQL 8.0 用mysql-connector-java-8.0.30.jar。版本不匹配的典型症状后面有专门一章说。前置环境我直接给你列个清单JDK 1.8Swing 自带不需要额外装、MySQL 5.7 或 8.0安装的时候把字符集选成 utf8mb4选错了后面中文全乱、一个你能用得顺手的数据库客户端Navicat 或 MySQL Workbench 都行命令行高手直接无视。这三样齐了再往下走。2.3 先导库还是先看代码我的建议是别急着看代码先把db_stu.sql导进 MySQL。原因很简单你运行系统第一个碰到的一定是数据库连接错误而不是业务 bug。提前把库导好等于先把后端这半边天稳住源码里就算有问题你也知道是代码逻辑问题还是环境问题。打开 MySQL 命令行输入密码之后执行mysql source /你的绝对路径/db_stu.sql;注意 source 后面的路径不允许带中文如果你的用户名是中文先把db_stu.sql复制到D:/或者C:/temp/这种纯英文路径下再执行。执行完输入show databases;能看到db_stu这个库就说明导入成功。下一步是改源码里的连接参数。3. 数据库接入db_stu.sql 的表设计、JDBC 连接参数与三处编码对齐3.1 建表思路管理员表 学生表的结构设计打开db_stu.sql看一下这套系统的表结构并不复杂。一般这种课程设计会拆成两张表一张存管理员账号密码一张存学生信息。管理员表负责登录校验学生表负责增删改查。典型的建表脚本长这样CREATE DATABASE IF NOT EXISTS db_stu DEFAULT CHARACTER SET utf8mb4; USE db_stu; CREATE TABLE t_admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录账号, password VARCHAR(50) NOT NULL COMMENT 密码明文存储课程设计要求, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT, sno VARCHAR(20) NOT NULL UNIQUE COMMENT 学号用 varchar 不用 int, name VARCHAR(50) NOT NULL COMMENT 姓名, sex VARCHAR(10) COMMENT 性别, age INT COMMENT 年龄, className VARCHAR(100) COMMENT 班级, major VARCHAR(100) COMMENT 专业, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );学号这一列特别注意用VARCHAR(20)而不是INT。很多 Excel 导出或手工录入的学号是 0 开头的比如20230001如果建表时用了 int 类型导入后前导零会被丢掉你查出来的数据就和原始数据对不上。这是写这类系统时非常典型的一个选型问题也是为什么我不建议你把所有字段都无脑设成 int 的原因。密码明文存储确实是隐患但课程设计老师通常只要求能登录不要求你上 BCrypt 加密。如果你愿意多走一步把密码改成 MD5 加盐存储也不难但改的时候要连登录校验逻辑一起改不然登录永远失败。我先按原资源的课程设计要求来不折腾。3.2 数据访问层的连接参数改哪里源码里负责连数据库的类一般叫DBUtil.java或DBHelper.java放在src下的com.stu.util包里。这个类里写了一堆常量你要改的就是这四行package com.stu.util; import java.sql.Connection; import java.sql.DriverManager; public class DBUtil { // 改成你自己的数据库账号别用 root 裸奔最好 private static final String USER root; private static final String PASSWORD 你自己的数据库密码; private static final String URL jdbc:mysql://localhost:3306/db_stu ?useUnicodetruecharacterEncodingutf8 useSSLfalse serverTimezoneAsia/Shanghai; public static Connection getConnection() throws Exception { // MySQL 8.0 必须用这个驱动类名5.7 用 com.mysql.jdbc.Driver Class.forName(com.mysql.cj.jdbc.Driver); return DriverManager.getConnection(URL, USER, PASSWORD); } }这里第一行Class.forName是最容易翻车的点。MySQL 5.7 时代驱动类名是com.mysql.jdbc.DriverMySQL 8.0 之后改成了com.mysql.cj.jdbc.Driver。你装了 8.0 的驱动 jar类名还是按旧教程写的com.mysql.jdbc.Driver启动时百分百报ClassNotFoundException。反过来你用 5.7 的驱动 jar 写新类名也会报同样的错。这个坑后面避坑章还会展开但提前在这里说一句先确认自己 MySQL 版本再填驱动类名。URL 里的参数每个都有用。useSSLfalse是关掉 SSL 加密握手本地开发不加这个MySQL 8.0 会警告。serverTimezoneAsia/Shanghai是必须的MySQL 8.0 默认时区是 UTC不加这个连接直接报时区错误。characterEncodingutf8管的是 Java 和 MySQL 之间的字符传输不加它中文写入数据库全变问号。这几个参数不是玄学是缺一个就出一个问题所以一次全带上最省事。3.3 连接参数速查表与三处编码对齐改完之后我建议你做一个验证动作在getConnection()下面写个 main 方法跑一下能打出连接成功再继续往下。别直接启动整个系统那样出了问题你不知道是连接的问题还是界面代码的问题。参数我整理成一份速查表参数值作用drivercom.mysql.cj.jdbc.DriverMySQL 8.0 驱动类5.7 用com.mysql.jdbc.Driverurljdbc:mysql://localhost:3306/db_stu指向 db_stu 库端口默认 3306useUnicodetrue启用 Unicode 字符集characterEncodingutf8Java 与 MySQL 传输编码useSSLfalse关闭 SSL本地开发提速serverTimezoneAsia/Shanghai指定时区8.0 必填userroot你的登录账号password你的密码不要用空密码关于编码记住一句话三处对齐才不乱码。第一处是建库脚本里的DEFAULT CHARACTER SET utf8mb4这决定了表里怎么存数据第二处是 JDBC 连接串带不带characterEncodingutf8这决定了 Java 往数据库传数据时用什么编码第三处是 IDE 里源码文件本身的编码IDEA 右下角把.java文件编码设为 UTF-8Windows 默认 GBK 会导致中文字符串常量在编译后就变了样。三处任何一处不一致中文就会出现那套经典的「录入是问号、查询也是问号」。4. Swing 增删改查到表单布局jgoodies-forms 参数与数据刷新4.1 jgoodies-forms 1.8.0 的表单布局写法这套系统的界面层是 Swing但布局管理器没有用原生的 GridBagLayout而是用了 jgoodies-forms。为什么要用这个库写 Swing 界面的都知道GridBagLayout 写起来又臭又长一个控件位置调半天。jgoodies-forms 的写法更接近声明式布局——你把行列规则定义好控件往格子里面放就行。典型的学生信息表单长这样import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.RowSpec; public JPanel buildStudentForm() { // 列定义pref 表示按内容自适应宽度dlu 是 jgoodies 的布局单位 FormLayout layout new FormLayout( right:pref, 6dlu, fill:120dlu, 8dlu, right:pref, 6dlu, fill:80dlu, pref, 6dlu, pref, 6dlu, pref, 6dlu, pref ); PanelBuilder builder new PanelBuilder(layout); builder.addLabel(学号, 1, 1); // 行 1 列 1 builder.add(new JTextField(), 3, 1); // 行 1 列 3 builder.addLabel(姓名, 5, 1); builder.add(new JTextField(), 7, 1); builder.addLabel(性别, 1, 3); builder.add(new JComboBox(new String[]{男, 女}), 3, 3); builder.addLabel(年龄, 5, 3); builder.add(new JTextField(), 7, 3); builder.addLabel(班级, 1, 5); builder.add(new JTextField(), 3, 5); builder.addLabel(专业, 5, 5); builder.add(new JTextField(), 7, 5); return builder.getPanel(); }这里面的列定义字符串是重点right:pref表示这一列右对齐且宽度自适应内容6dlu是列间距fill:120dlu表示这一列固定宽度 120dl u且自动拉伸填充。行定义同理几乎不用写 setBounds 和 setAlignment控件位置全靠行列坐标控制。坐标写法是行号, 列号从 1 开始计数——很多第一次接触 jgoodies 的人会下意识从 0 开始然后发现所有控件乱成一团记住这一点能省下一晚上的调试时间。PanelBuilder是 jgoodies-forms 的构建器类addLabel和add方法都会返回CellConstraints对象所以你可以链式调用继续指定下一个控件位置。但lib/里已经有 sources jar 了遇到布局问题直接点进去看FormLayout的源码比网上搜半天靠谱得多——这就是作者附赠源码包最大的价值。4.2 增删改查的数据访问层与按钮事件联动界面层搭好了业务层就是最标准的 JDBC 操作。这里有一个新手容易踩的线用Statement拼 SQL 还是用PreparedStatement参数化查询。源码里的StudentDao采用后者这是对的照着写就行。典型的新增学生方法如下public boolean addStudent(Student stu) throws Exception { String sql INSERT INTO t_student (sno, name, sex, age, className, major) VALUES (?, ?, ?, ?, ?, ?); Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, stu.getSno()); ps.setString(2, stu.getName()); ps.setString(3, stu.getSex()); ps.setInt(4, stu.getAge()); ps.setString(5, stu.getClassName()); ps.setString(6, stu.getMajor()); int rows ps.executeUpdate(); ps.close(); conn.close(); return rows 0; }用?占位符配合setString、setInt的好处是第一SQL 注入这条路基本被封死第二你不需要手工处理字符串里的单引号转义第三代码读起来清楚哪一列填什么一眼就能对上。我在实际改别人代码的时候见过太多用Statement拼字符串的写法一个没拼对整条 SQL 就废了而且报错还不能直接看调试成本翻倍。这里建议你把conn的关闭放到finally块里或者用 try-with-resources 自动关闭课程设计虽然不扣分但这个习惯早点养成只有好处。删除和修改的写法套路一样只是 SQL 语句不同。删除是按主键删DELETE FROM t_student WHERE id ?修改是UPDATE把所有字段重写一遍。查询列表用executeQuery()拿ResultSet然后循环逐条封装成Student对象public ListStudent queryAll() throws Exception { ListStudent list new ArrayList(); String sql SELECT * FROM t_student ORDER BY create_time DESC; Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery(); while (rs.next()) { Student stu new Student(); stu.setId(rs.getInt(id)); stu.setSno(rs.getString(sno)); stu.setName(rs.getString(name)); stu.setSex(rs.getString(sex)); stu.setAge(rs.getInt(age)); stu.setClassName(rs.getString(className)); stu.setMajor(rs.getString(major)); list.add(stu); } rs.close(); ps.close(); conn.close(); return list; }排序这里我用的是ORDER BY create_time DESC也就是最新录入的学生显示在最上面。原资源里如果用id排序效果也一样因为自增主键本身就是录入顺序。两者区别不大但如果你做「按学号查询」「按姓名模糊查询」的扩展功能建议统一走PreparedStatement把查询条件也做成?参数避免拼接字符串注入。4.3 列表刷新的两个常见翻车点增删改查全部写在 Dao 里界面按钮的监听器只需要调用对应方法然后刷新表格。但这里有两个高频翻车点十个人里面有六七个会踩到。第一个翻车点新增或删除成功后表格不刷新必须把窗口关了重开才能看到数据。原因是按钮监听器里只调了addStudent()没有重新加载表格。正确做法是在操作成功后重新查一次数据然后把新的数据填进DefaultTableModelprivate void refreshTable() { // 重新查库拿到最新列表 ListStudent students dao.queryAll(); // 清空旧数据 model.setRowCount(0); // 逐行填入新数据 for (Student stu : students) { model.addRow(new Object[]{ stu.getId(), stu.getSno(), stu.getName(), stu.getSex(), stu.getAge(), stu.getClassName(), stu.getMajor() }); } // 刷新表格视图 table.setModel(model); }第二个翻车点更隐蔽在JTable里删除选中的一行结果删错人了。原因是你点了第 3 行拿到的row是视图行号但表格数据经过排序或筛选后视图行号跟数据库里的主键id不一定一一对应。正确做法是通过表格行号反查数据模型里的id再拿这个id去执行删除。别直接用row当作id这是 SwingJTable交互里最经典的错位问题。事件监听这块还有一个小细节ActionListener里的代码跑在 EDT事件分发线程上你在里面做数据库查询会暂时卡住界面数据量小感觉不到数据量大了窗口会假死。这个项目的几百条学生数据不会有明显体感但如果以后你拿这套骨架做更大的项目记得用SwingWorker把耗时的数据库操作挪到后台线程去。这个属于进阶优化先记住有这回事就行。5. 避坑活点地图驱动冲突、乱码、空列表五个高频现场5.1 ClassNotFoundExceptionmysql 5 跟 mysql 8 的驱动类名不一样现象启动系统控制台第一行就是java.lang.ClassNotFoundException: com.mysql.jdbc.Driver程序直接终止。原因你的lib/里放的是 MySQL 8.0 的驱动 jar但代码里Class.forName写的还是 5.7 时代的旧类名或者反过来你的驱动 jar 是 5.7 的类名却写成了 8.0 的com.mysql.cj.jdbc.Driver。解决先确认 MySQL 版本在命令行执行mysql --version然后让驱动 jar、驱动类名、连接串三者版本对齐——MySQL 5.7 配mysql-connector-java-5.1.49.jar配旧类名MySQL 8.0 配 8.0.x 的驱动配新类名。别混搭混搭只有两种结果要么现在的报错要么连上之后诡异报错。5.2 时区报错与中文乱码连接串和字符集三处对齐现象连接 MySQL 8.0 时直接抛The server time zone value й is unrecognized或者查询结果显示???。原因其实是两个问题叠加时区没设置MySQL 8.0 默认时区不是东八区Connection 建立时被拒绝字符集没对齐建库、连接串、IDE 文件编码三处不一样。解决连接串里一次性带上serverTimezoneAsia/ShanghaicharacterEncodingutf8建库脚本指定DEFAULT CHARACTER SET utf8mb4IDE 里所有.java文件编码设为 UTF-8。我之前帮人排查过这个问题他折腾了一下午以为是 MySQL 没装好结果只是连接串里少了characterEncodingutf8补上之后一切正常——这种问题最气人因为它不是逻辑错误纯粹是环境参数没写全。5.3 点击按钮没反应先查事件线程和监听器现象窗口能启动表格也有数据但点「新增」「删除」「修改」任何一个按钮都没反应。原因大概率不是 SQL 的问题而是监听器根本没注册。我用 IDEA 打开别人代码的时候经常看到两种写法写了button.addActionListener(this)但类没实现ActionListener接口或者在main方法里 new 了窗口却忘了把按钮绑定到控制器。解决先看按钮有没有注册监听器再看监听器方法体里的逻辑有没有被if条件挡住。还有一个容易被忽略的如果你的按钮代码里写了Thread.sleep(3000)界面会假死看起来就像没反应其实是卡住了去掉所有Thread.sleep改用SwingUtilities.invokeLater做异步刷新。5.4 窗口能启动但列表是空的可能连错了库现象系统启动正常登录也成功但学生信息列表一张表空荡荡。原因不是没有数据而是你的连接串指向了一个同名的空库或者SELECT语句查错了表名。我见过最离谱的一次是连接串写的是jdbc:mysql://localhost:3306/test而db_stu.sql的建表脚本建在了db_stu库里两套库的表结构一模一样但数据永远查不到。解决在queryAll()方法里临时加一行SELECT DATABASE()验证当前连的是哪个库或者在 SQL 里把表名写成全限定名t_student。用show tables看一眼库里到底有没有表、表里有没有数据比盯着代码空想要快得多。5.5 MySQL 启动失败3306 端口被占现象你双击启动 MySQL 服务提示启动失败或者系统能启动但 Java 连不上报Communications link failure。原因十有八九是 3306 端口被别的进程占了——可能是你自己之前装过一次 MySQL 没卸干净也可能是别的软件顺手用了这个端口。解决命令行执行netstat -ano | findstr 3306看到占用进程的 PID 之后去任务管理器查是什么程序确认不是系统关键进程直接结束它然后重启 MySQL 服务。如果确定是旧版 MySQL 残留先把旧服务删掉sc delete 服务名再装新版。这个话题展开又是一篇长文但你这个场景下记住一条就够了先查端口再卸旧版最后装新版。6. 交付思维冷启动验证、固定演示数据与一份能救命的运行说明到这一步系统你已经能跑起来了但「你自己能跑」和「交给别人也能跑」完全是两码事。我每次拿到这种资源包跑通之后第一件事不是写代码而是做一次冷启动验证模拟一个全新的环境——把数据库drop掉把db_stu.sql重新导一遍然后清掉我临时加的测试数据再把项目重新编译启动。这套流程走完不出错才说明这个资源是完整、可复现的。冷启动验证的标准动作是下面这三条一个都不能少mysql DROP DATABASE db_stu; mysql source D:/db_stu.sql; mysql USE db_stu; SHOW TABLES;第一条是删掉现有库模拟你刚下载下来什么都没配的初始状态。第二条是重导脚本确认db_stu.sql本身没有问题。第三条是看表清单确认t_admin和t_student都在。这个验证做完了你才敢说「照着文档走一遍必能跑」。我见过太多的资源包作者自己环境里能跑打包的时候却漏了某个依赖包或某张表的语句下载的人一跑就死最后变成求助帖——冷启动验证就是为了避开这个尴尬。演示数据也要固化。你调试的时候可能在表里录了一堆「测试一号」「测试二号」的脏数据交作业之前记得清理干净只留两三条带真实感的样例数据比如学号姓名性别年龄班级专业20230001张明男20计科2301计算机科学与技术20230002李婷女19计科2301计算机科学与技术截图用的、演示用的数据必须是同一份别截图是一套数据现场演示又是另一套老师一问数据对不上就尴尬了。然后导出一份干净的db_stu.sql导出的命令用mysqldump -u root -p --default-character-setutf8 db_stu D:/db_stu.sql这里有一个容易踩的细节mysqldump导出时如果不指定字符集Windows 命令行默认可能是 GBK导出的 SQL 文件里中文注释会乱码下次重新导入时表结构没坏但数据全乱。所以--default-character-setutf8这个参数一定要带血泪经验。最后给项目留一份运行说明。很多人觉得自己记得住环境怎么配过两个月再看全忘光。这张小抄我建议你做成一个 TXT 放在工程根目录内容包括JDK 版本、MySQL 版本、驱动 jar 版本、数据库账号密码、连接串参数、管理员登录名密码。表格就是现成的模板配置项值JDK 版本1.8MySQL 版本8.0.x驱动 jarmysql-connector-java-8.0.30.jar数据库名db_stu连接串jdbc:mysql://localhost:3306/db_stu?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai管理员账号admin管理员密码admin123资源包作者当初的默认账号一般都在源码里写死或者写在db_stu.sql的INSERT INTO t_admin语句里你看一眼就能找到。如果密码不是你想要的直接在 SQL 里改掉再重新导入就行。从那以后我每次拿到这种带数据库的 Swing 项目都强制自己走一遍「删库、导库、冷启动、清理测试数据」四连不给侥幸留一点空间。你把这个习惯也带上等你哪天真要交付项目或者答辩演示的时候会感谢今天这几分钟。希望帮到你。本文还有配套的精品资源点击获取