☰
Java+MySQL学生信息管理系统源码解析:JDBC增删改查与Swing实战
2026/9/30 4:53:58 网站建设 项目流程

简介:这份资源面向Java初学者与需要完成课程设计的学生,提供一套基于Java Swing与MySQL的学生信息管理系统实现方案,重点解决使用JDBC完成学生信息增删改查的典型课设需求。压缩包内共1个PDF文件,大小约135KB,以图文形式呈现项目源码与数据库设计,涵盖建库建表语句、model-dao-view分层结构以及管理员、学生实体类的定义,便于读者理解各模块职责与代码组织方式。资源中给出了admin与student两张表的完整SQL,包含学号、姓名、院系、籍贯、学分、邮箱、联系方式等字段,并附有示例数据,可直接用于本地环境搭建与调试。目前已有5010人学习下载,适合作为Java数据库编程入门、Swing界面开发练习及课程设计参考,帮助读者快速掌握JDBC操作与分层开发思路。

1. 从一份 2016 年的课设源码说起:Java+MySQL 学生信息管理系统到底能跑出什么

如果你正在搜「Java学生信息管理系统源码」「Java课程设计案例源码」,大概率是课设 deadline 逼近,或者想找一个能跑通 JDBC 增删改查的最小闭环项目练手。这份基于 Java Swing + MySQL 的学生信息管理系统,开发环境是 jdk7 + MySQL5 + win7,代码结构走的是经典的 model-dao-view 三层,核心就是用 JDBC 把学生信息的增删改查串起来,再套一层 Swing 界面。它不花哨,没有 Spring、没有 MyBatis,但正因为「裸奔」,反而适合拿来理解 JDBC 到底怎么连库、DAO 怎么封装、Swing 表格怎么和数据库联动。适合谁?一是课设需要交差、想快速拿到可运行源码的同学;二是刚学完 Java 基础、想找一个完整 CRUD 项目把面向对象编程 Java 的封装、继承、多态落地一遍的人。下面我按「拿到源码怎么跑起来 → 每层代码在干什么 → 容易翻车的地方 → 怎么把它改得更像样」的顺序拆一遍。

2. 把源码跑起来:建库建表、导依赖、改配置三步走

2.1 先建库建表,别急着打开 IDE

很多人拿到源码第一反应是直接 import 进 IntelliJ IDEA 然后点运行,结果控制台一片红。血泪经验是:先把数据库准备好,再动代码。这份项目的建库建表语句在正文里给全了,直接复制到 Navicat for MySQL 或者命令行里执行即可。注意admin表里预置了一条admin/admin/admin的记录,这是登录用的,别删。

-- 建库 CREATE DATABASE student DEFAULT CHARSET=utf8; -- 管理员表 DROP TABLE IF EXISTS `admin`; CREATE TABLE `admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; INSERT INTO `admin` VALUES (1,'admin','admin','admin'); -- 学生表 DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `sno` varchar(20) NOT NULL, `department` varchar(20) NOT NULL, `hometown` varchar(20) NOT NULL, `mark` varchar(20) NOT NULL, `email` varchar(20) NOT NULL, `tel` varchar(20) NOT NULL, `sex` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8; INSERT INTO `student` VALUES (18,'张三','001','信息科学技术学院','辽宁','80','zhangsan@163.com','13888888888','男'), (19,'李四','002','理学院','上海','70','lisi@sina.com','13812341234','男'), (20,'王五','003','外国语学院','北京','88','wangwu@126.com','13698765432','女');

这段 SQL 的逻辑很直白:admin表只管登录,student表存学生全字段。参数上要注意sno是学号,虽然设了varchar(20)但没加唯一索引,这意味着数据库层面不拦重复学号,重复校验得靠 DAO 里的queryBySno手动做——这是后面避坑章节要重点说的点。字符集统一utf8,如果你本地 MySQL 是 8.0 且默认utf8mb4,插中文一般没问题,但连接串里的编码参数别写错。

2.2 导入项目与依赖:JDBC 驱动是唯一的硬依赖

项目本身没有 Maven 的pom.xml(2016 年的课设风格),所以依赖得手动加。唯一必须的 jar 是 MySQL 的 JDBC 驱动,也就是mysql-connector-java。在 IntelliJ IDEA 里操作路径是:File → Project Structure → Libraries → 加号 → 选中你下载的mysql-connector-java-5.x.jar。版本要和你的 MySQL 对上:MySQL 5.x 配5.1.x的驱动,MySQL 8.x 则要用8.0.x驱动,否则会撞上this version of the jdbc driver is only compatible with...这类版本不匹配报错。

# 如果用命令行编译运行,classpath 要带上驱动 javac -encoding UTF-8 -cp ".;mysql-connector-java-5.1.49.jar" com/student/**/*.java java -cp ".;mysql-connector-java-5.1.49.jar" com.student.view.LoginView

Windows 下 classpath 分隔符是分号;,Linux/Mac 是冒号:,这点搞错会直接报ClassNotFoundException。另外源码里用了Class.forName(AppConstants.JDBC_DRIVER)这种老式加载驱动写法,MySQL 8 驱动类名变成了com.mysql.cj.jdbc.Driver,连接串也要加时区和 SSL 参数,否则会报mysql ssl连接错误或者时区异常。

2.3 改 AppConstants:连接串、账号、密码三处对齐

项目把数据库配置抽到了AppConstants里,这是好习惯,改一处就行。你需要确认四个常量:JDBC_DRIVER、JDBC_URL、JDBC_USERNAME、JDBC_PASSWORD。URL 的典型写法是jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8。如果你本地 MySQL 8,建议改成:

public static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; public static final String JDBC_URL = "jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false"; public static final String JDBC_USERNAME = "root"; public static final String JDBC_PASSWORD = "你的密码";

serverTimezone不加,MySQL 8 会直接抛时区异常;useSSL=false是本地开发图省事,生产环境别这么干。改完这三处,运行LoginView,用admin/admin登录,能进主界面看到学生列表,就说明整条链路通了。

3. model-dao-view 三层拆解:JDBC 增删改查是怎么被封装起来的

3.1 model 层:两个 POJO 撑起数据载体

Admin和Student两个类就是标准的 POJO,私有字段加 getter/setter。Student有 9 个字段:id、sno、name、sex、department、homeTown、mark、email、tel。注意mark(学分)用的是String而不是int,这是这份源码一个偷懒的地方——数据库里也是varchar(20)。好处是省去了类型转换,坏处是你没法在数据库层做数值排序和统计。如果你要按学分排序,得在 Java 里转Integer.parseInt,还得处理空值和非法字符。面向对象编程 Java 里 POJO 的职责就是承载数据,不掺业务逻辑,这一点它做到了。

3.2 DBUtil:单例 + PreparedStatement 的 JDBC 封装

DBUtil是整个项目的黑匣子,把 JDBC 的重复代码收拢了。它用饿汉式单例(getDBUtil)保证全局一个实例,内部持有Connection、PreparedStatement、ResultSet。核心方法就四个:两个executeUpdate(带参和不带参)、两个executeQuery(带参和不带参)。带参版本用Object[]接收参数,循环ps.setObject(i+1, obj[i])填充占位符——这就是jdbc增删改查里防 SQL 注入的标准姿势。

public int executeUpdate(String sql, Object[] obj) { int result = -1; if (getConn() == null) return result; try { ps = conn.prepareStatement(sql); for (int i = 0; i < obj.length; i++) { ps.setObject(i + 1, obj[i]); // 占位符从 1 开始 } result = ps.executeUpdate(); close(); // 注意:这里更新完就关了连接 } catch (SQLException e) { e.printStackTrace(); } return result; }

参数说明:sql是带?的预编译语句,obj是按顺序对应的参数数组。这里有个细节坑——executeUpdate带参版本执行完直接调了close(),把连接也关了;而executeQuery带参版本没关,留给调用方在destroy()里关。这种不对称设计容易让新手困惑,后面避坑章节细说。getConn()里做了懒加载:连接为空或已关闭才重新DriverManager.getConnection,算是简易的连接复用。

3.3 DAO 层:BaseDAO 工厂 + 两个具体 DAO

BaseDAO是个抽象类,用getAbilityDAO(DAO dao)这个静态工厂方法根据枚举返回AdminDAO或StudentDAO单例。它持有protected final DBUtil db,子类直接用。destroy()方法负责关ResultSet和连接。AdminDAO只有一个queryForLogin,用select * from admin where username=? and password=?判断登录,返回 boolean。StudentDAO是重头戏,五个方法:add、delete、update、queryByName、list。

add方法先调queryBySno查学号是否存在,存在就返回 false,不存在才 insert。update同样先校验学号存在,再用update student set ... where name=? and sno=?更新。delete用name + sno双条件删除。list方法做分页,showNum=15,用limit ?,?实现,beginNum = (pageNum-1)*showNum。queryByName用like %name%模糊查。所有查询结果最终被buildList塞进List<Student>,再由buildResult转成String[][]二维数组给 Swing 表格用。

// 分页查询核心 int beginNum = (pageNum - 1) * showNum; String sql = "select * from student limit ?,?"; Integer[] param = { beginNum, showNum }; rs = db.executeQuery(sql, param);

参数说明:pageNum从 1 开始,showNum固定 15。limit的第一个参数是偏移量,第二个是条数。这里用Integer[]而不是String[],因为setObject能识别 Integer 类型,MySQL 的 limit 也接受整型。注意buildList里stu.setId(i+1)是重新编的序号,不是数据库真实 id,这会导致删除时如果按界面显示的 id 去操作会对不上——这是个隐藏坑。

3.4 view 层:Swing 表格 + 事件监听串起交互

MainView继承JFrame,北边放搜索框和按钮,中间放JTable,南边放分页按钮。表格列由String[] column定义,数据来自StudentDAO.list(currPageNum)返回的二维数组。搜索框绑了KeyListener,回车触发FindListener调queryByName。分页按钮控制currPageNum增减,再重新list刷新表格。AddView、DeleteView、UpdateView是三个独立窗口,分别调StudentDAO的add、delete、update。整个 view 层就是「收集用户输入 → 调 DAO → 刷新表格」的循环,没有 MVC 框架,纯手写事件驱动。

4. 避坑与排查:这份源码跑不通的五个高频原因

4.1 现象:登录报 ClassNotFoundException,驱动找不到

原因:JDBC 驱动 jar 没加进 classpath,或者 IDEA 里加了但没勾选到模块的 dependencies。解决:Project Structure → Modules → Dependencies 确认驱动在列表里且 scope 是 Compile;命令行运行则确认-cp里带了 jar 的完整路径。MySQL 8 还要确认驱动类名是com.mysql.cj.jdbc.Driver而不是老的com.mysql.jdbc.Driver。

4.2 现象:插入中文变问号或乱码

原因:数据库、表、连接串三处字符集不一致。解决:建库建表用utf8或utf8mb4,连接串加useUnicode=true&characterEncoding=utf8,IDEA 的 File Encoding 设成 UTF-8。如果 MySQL 是 8.0 且表是utf8mb4,连接串的characterEncoding也建议写utf8(驱动会映射),别写utf8mb4有些老驱动不认。

4.3 现象:更新或删除后,再查询报连接已关闭

原因:DBUtil.executeUpdate带参版本执行完直接close()关了连接,而StudentDAO.update里在db.executeUpdate之后又调了destroy(),destroy里再关一次。虽然close()对已关闭连接通常不抛异常,但如果中间又穿插了别的查询,就会撞上Connection is closed。解决:统一关闭策略,要么 DBUtil 不关、由 DAO 的destroy统一关,要么 DBUtil 关、DAO 不再重复关。我一般会把executeUpdate里的close()去掉,交给destroy()收尾。

4.4 现象:学号重复插入没被拦住

原因:student表的sno字段没有唯一约束,queryBySno的校验存在并发窗口——两个请求同时查都说不存在,然后都插入。课设单机跑一般碰不到,但如果你拿它当模板做正式点的东西,这就是隐患。解决:给sno加UNIQUE索引,数据库层兜底,DAO 层的校验作为友好提示保留。

4.5 现象:分页翻到最后一页后继续点「下一页」表格空白

原因:MainView里maxPageNum写死 99,但实际数据可能只有 3 条,currPageNum超过真实页数时list返回 null,表格被清空。解决:在list返回 null 时保持当前页不变,或者先查count(*)算出真实总页数再限制翻页范围。常见做法是加一个getTotalCount方法,maxPageNum = (total + showNum - 1) / showNum。

5. 进阶改造:从「能跑」到「像样」的三个具体动作

5.1 把 mark 改成 int 并加校验

mark用 String 存是这份源码最别扭的地方。改造步骤:数据库ALTER TABLE student MODIFY mark int(11),Student类字段改private int mark,AddView和UpdateView里输入框取值时用Integer.parseInt并 try-catch 处理非数字。这样list方法就能支持按学分排序,SQL 加order by mark desc即可。注意历史数据里如果有非数字的 mark,改字段前先清洗。

5.2 用连接池替掉手写单例连接

DBUtil每次getConn都新建连接,频繁增删改查下性能很差。常见做法是引入 Druid 或 HikariCP,把DriverManager.getConnection换成dataSource.getConnection()。以 HikariCP 为例:

HikariConfig config = new HikariConfig(); config.setJdbcUrl(AppConstants.JDBC_URL); config.setUsername(AppConstants.JDBC_USERNAME); config.setPassword(AppConstants.JDBC_PASSWORD); config.setMaximumPoolSize(10); HikariDataSource ds = new HikariDataSource(config); // 之后 conn = ds.getConnection();

参数说明:maximumPoolSize按并发量调,课设 10 足够;连接用完必须close()归还池子,而不是真关。改造后DBUtil的getConn和close逻辑要相应调整,close变成归还连接。

5.3 给表格加真实 id 隐藏列,修掉删除错位

前面说过buildList里setId(i+1)是假 id,导致界面显示的行号和数据库真实 id 脱节。改造方法:buildList里改成stu.setId(rs.getInt("id")),buildResult第一列仍放 id 但界面上可以把这一列隐藏(jTable.getColumnModel().getColumn(0).setMinWidth(0)之类),删除和更新时从选中行拿到真实 id 去操作。这样delete的 SQL 就可以简化成delete from student where id=?,比name + sno双条件可靠得多——毕竟重名重学号的极端情况虽然少,但真碰上就是删错人的事故。

从那以后我每次拿到这种课设级源码,都强制先跑一遍「建库 → 改配置 → 登录 → 增删改查 → 翻页」五步冒烟测试,再动任何一行代码。这份 Java+MySQL 学生信息管理系统源码结构清晰、依赖极简,作为 JDBC 和 Swing 的练手底子完全够用,但上面这些坑你得心里有数。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询