
简介这是一份基于Eclipse与MySQL开发的Java学生信息管理系统源码面向Java初学者与课程设计场景完整实现登录注册、三种身份权限管理和学生成绩的增删改查。系统分为管理员、教师、学生三类角色管理员和教师可维护学生信息学生仅可查询能帮助练习Swing界面、JDBC数据库操作和分层开发思路。压缩包共44个文件其中17个Java源文件对应核心业务与界面逻辑18个class为编译输出另含jar依赖包、数据库相关配置及两张界面预览图整体仅616KB结构简洁便于学习。已有6474人学习下载适合用于期末作业、毕业设计参考或个人练手。解压后可直接在eclipse中导入配合MySQL运行读者可从中掌握多角色权限控制的实现方式以及登录模块与数据操作模块的完整组织方法。1. Java学生信息管理系统一个课程设计项目为什么值得认真做一遍如果你搜过“Java课程设计案例源码”大概率会碰到这个名字——Java学生信息管理系统eclipseMySQL。它几乎是Java后端入门阶段出现频率最高的练手项目也是很多计算机专业学生第一次把Java SE、JDBC、MySQL和Eclipse这四样东西拼在一起的机会。这个标题背后其实是一套完整的CRUD思维连数据库、查数据、展示到界面、再把用户的操作写回数据库。它不炫技但把Java工程师日常最常用的一条链路走通了。这个系统适合谁两类人。一类是刚学完Java基础、面对“面向对象编程java”还停留在概念阶段需要一个真实项目来把类、对象、继承、接口落到代码里的新手另一类是准备Java基础面试题、想用一个小项目串讲JDBC和SQL细节的求职者。它的价值不在于功能多强大而在于你能在Eclipse里亲手跑通一条数据从MySQL表到Java对象再到界面控件的完整通道。本文直接按我实际做这类项目的顺序来写环境怎么配、表怎么建、代码怎么分层、坑在哪里。2. 环境准备JDK、Eclipse与MySQL的版本搭配和第一个连接2.1 版本组合的常见搭配JDK 8、Eclipse与MySQL 5.7做学生信息管理系统这类中小型Java项目最稳妥的组合是JDK 8 Eclipse2020年以后版本均可 MySQL 5.7。为什么不是越新越好JDK 8在Java面试和学习路线里依然是主流Eclipse对JDK 8的兼容性最好而MySQL 5.7的安装配置比8.0简单默认认证插件是mysql_native_password对老版本JDBC驱动友好。如果你用JDK 11以上语法上没大问题但有些Eclipse版本需要额外配置模块访问权限对新手来说属于不必要的麻烦。MySQL 8.0不是不能用但有一系列连锁问题。例如8.0默认的caching_sha2_password认证插件会让mysql-connector-java 5.x版本的驱动直接报认证失败必须换8.0.x的驱动同时连接URL里要额外加allowPublicKeyRetrievaltrue。这些对熟悉Java环境配置的人还好对刚搭好环境的新手来说就是劝退现场。所以我的建议很直接如果没有特殊要求装MySQL 5.7省下的时间用来写业务代码。Eclipse的选择上直接去官网下Eclipse IDE for Enterprise Java and Web Developers版本别下Eclipse IDE for Java Developers——后者不带Web和数据库透视图虽然学生系统的纯Java Swing界面用不到Web但Enterprise版内置了Database Development视图调试SQL时能少装一个插件。下载后解压即用不需要安装这点比IDE要省心。2.2 用eclipse连接MySQL驱动JAR、Build Path和最小连接代码环境变量配置是卡住新手的第一道坎。JDK装好后需要在系统变量里新建JAVA_HOME指向JDK安装目录再在Path里加%JAVA_HOME%\bin。命令行执行java -version能输出版本号就算通过。MySQL安装时如果选了“标准配置”默认端口3306字符集一定要选utf8否则后面中文乱码会四处冒头。接下来是JDBC驱动的引入。到MySQL官网下载mysql-connector-java的JAR包5.1.49版本对MySQL 5.7最稳。在Eclipse里右键项目 → Build Path → Configure Build Path → Libraries → Add External JARs选到这个JAR。这一步没做对的话后面所有数据库操作都会报ClassNotFoundException。验证连接是否打通用一个独立的测试类import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBTest { public static void main(String[] args) { // 驱动类全名5.x和8.x这个类名是相同的 try { Class.forName(com.mysql.jdbc.Driver); } catch (ClassNotFoundException e) { System.out.println(驱动类没找到检查JAR是否加入Build Path); e.printStackTrace(); return; } // 连接参数地址、端口、库名、用户名、密码 String url jdbc:mysql://localhost:3306/student_db?useUnicodetruecharacterEncodingutf8; try (Connection conn DriverManager.getConnection(url, root, 123456)) { System.out.println(连接成功 conn.getClass().getName()); } catch (SQLException e) { System.out.println(连接失败错误码 e.getErrorCode()); e.printStackTrace(); } } }这段代码里的三个关键点Class.forName在JDBC 4.0之后可以省略但写上它能第一时间暴露驱动JAR缺失的问题URL里的useUnicode和characterEncoding参数负责让中文以UTF-8进出数据库try-with-resources语法确保Connection自动关闭避免连接泄漏。2.3 连接URL的常见参数SSL、时区和编码的设置边界连接URL是最容易复制错的地方。常见写法是jdbc:mysql://localhost:3306/student_db但这只是最小可运行形式。如果你的MySQL是5.7建议加useSSLfalse——5.7默认SSL是关闭的但加上这个参数能避免某些驱动版本自动尝试SSL握手导致连接变慢。如果用的MySQL 8.0URL要变成String url jdbc:mysql://localhost:3306/student_db ?useSSLfalseallowPublicKeyRetrievaltrue useUnicodetruecharacterEncodingutf8 serverTimezoneAsia/Shanghai;serverTimezone是MySQL 8.0的必填参数不填会报时区错误。allowPublicKeyRetrievaltrue配合caching_sha2_password认证插件使用不加上去会报Public Key Retrieval is not allowed。这些参数不是背出来的而是遇到对应报错后能想到去加所以我把它们放在环境准备这一章里因为它们是新手查“mysql连接失败”时最容易搜到但最常被误导的内容。建立连接之后下一步要做的不是写业务代码而是把数据模型定下来。这是很多Java课程设计项目翻车的起点——代码写了一半发现表结构缺字段再回头改表、改DAO、改界面三重修改。3. 数据库设计先行建表SQL的细节与DAO层的读写规范3.1 建库建表把学生、课程、成绩三张表的关系一次定对学生信息管理系统最简版本至少需要三张表学生表、课程表、成绩表。学生表和课程表是多对多关系通过成绩表关联。设计表结构时有一个常见误区把成绩字段直接放在学生表里。这样做会在后续扩展课程功能时被迫频繁alter table正确的做法是独立的成绩表每一行代表一个学生修一门课得到的分数。-- 建库时指定字符集这是后面不出现中文乱码的第一道防线 CREATE DATABASE IF NOT EXISTS student_db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE student_db; -- 学生表 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 学号自增主键, stu_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号业务编号如2024001, name VARCHAR(50) NOT NULL COMMENT 姓名, gender CHAR(2) DEFAULT 男 COMMENT 性别, birthday DATE DEFAULT NULL COMMENT 出生日期, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 课程表 CREATE TABLE course ( id INT PRIMARY KEY AUTO_INCREMENT, course_name VARCHAR(50) NOT NULL, credit INT DEFAULT 2 COMMENT 学分 ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 成绩表学生和课程的多对多关系通过这里表达 CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, score DECIMAL(5,2) DEFAULT 0 COMMENT 成绩保留两位小数, UNIQUE KEY uk_stu_course (student_id, course_id), CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student(id) ON DELETE CASCADE, CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8;这里有几个细节值得说明。第一student表里既有id又有stu_noid是给程序用的自增主键stu_no是给用户看的业务学号两者分离。第二score表加了联合唯一键防止同一个学生同一门课被插入两条记录。第三外键的ON DELETE CASCADE保证删除学生时成绩自动清理避免残留脏数据。ENGINEInnoDB是必须的只有InnoDB支持外键和事务搜过“mysql设置默认值为0”这类问题的同学会注意到DEFAULT 0这种写法对数字字段有效对VARCHAR字段必须加引号。3.2 DAO层读写PreparedStatement的参数占位与结果集映射表结构定了Java代码的分层就顺了。常见做法是三层实体类model对应表结构DAO层Data Access Object负责SQL执行界面层view负责交互。很多课程设计项目把SQL直接写在界面按钮的点击事件里这种写法在小项目里能跑但一旦要加功能就会变成一堆复制粘贴的代码。一个规范的DAO方法长这样import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class StudentDao { // 新增学生 public boolean addStudent(Student stu) { String sql INSERT INTO student (stu_no, name, gender, birthday, phone) VALUES (?, ?, ?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, stu.getStuNo()); ps.setString(2, stu.getName()); ps.setString(3, stu.getGender()); // java.sql.Date.valueOf接受yyyy-MM-dd格式字符串 ps.setDate(4, Date.valueOf(stu.getBirthday())); ps.setString(5, stu.getPhone()); return ps.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } } // 按学号精确查询 public Student findByStuNo(String stuNo) { String sql SELECT id, stu_no, name, gender, birthday, phone FROM student WHERE stu_no ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, stuNo); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { Student stu new Student(); stu.setId(rs.getInt(id)); stu.setStuNo(rs.getString(stu_no)); stu.setName(rs.getString(name)); // 结果集取字段时用列名取下标容易因SELECT顺序变化而出错 return stu; } } } catch (SQLException e) { e.printStackTrace(); } return null; } }这段代码的核心是PreparedStatement。它相比Statement有两个优势参数用?占位避免了字符串拼接SQL带来的注入风险SQL语句提前预编译重复执行时性能更好。在Java面试里“怎么保证数据一致性”或“如何防SQL注入”这类问题答案的核心就是PreparedStatement加事务。结果集映射部分有一个典型翻车点rs.getInt(id)里的列名必须和SELECT语句里出现的列名一致而不是和表字段名一致。比如你的SQL写的是SELECT id AS stu_id FROM student那这里就得写rs.getInt(stu_id)。这个坑在复制别人代码时最容易踩。3.3 DBUtil的实现连接复用和被忽视的关闭顺序每个DAO方法都写一遍DriverManager.getConnection既啰嗦又容易出泄漏问题所以通常抽一个DBUtil工具类。前面测试用try-with-resources自动关闭了连接但实际项目里Connection是从DriverManager每次新获取的频繁创建销毁在高并发表情下会拖垮数据库。不过对学生管理系统这种低并发项目每次新连接完全够用不必上连接池。数据源换用连接池如Druid或HikariCP属于进阶优化等系统真的需要跑在公网服务器上再考虑。DBUtil里需要写一个专门的关闭方法注意关闭顺序要与打开顺序相反先关ResultSet再关Statement最后关Connection。用try-with-resources可以自动处理但如果你的代码结构里Connection要跨越多个方法传递就必须手动在finally块里关闭。手动关闭的写法要判断null避免空指针。写DAO时还有一处要克制不要在DAO里做业务判断。比如“删除学生前先检查他有没有成绩记录”这种逻辑应该放在Service层。DAO只负责一件事——执行SQL并返回结果。这样项目答辩时你能清晰地说出每一层的职责而不是被问到“你这个功能是哪个类实现的”时答不上来。4. 把主流程跑通从登录窗口到学生信息的增删改查4.1 包结构怎么摆Eclipse工程目录与类的职责边界环境准备好、三张表建好、DAO抽出来后接下来的核心工作是把界面和业务串起来。在Eclipse里新建Java Project时Package命名建议用com.xxx.student这样的反域名格式下面分四个包model实体类对应数据库表字段和表列一一对应。dao数据访问层只包含SQL操作。service业务逻辑层比如登录校验、成绩合法性判断。view界面层Swing的JFrame和事件监听都放这里。这种分层不是学院派的形式主义。学生信息管理系统最常见的翻车场景就是登录窗口的按钮事件里直接写JDBC查询查询完又直接把结果set到另一个窗口的文本框里。第一版确实跑得通但后面加“修改密码”功能时你不得不在界面类里再复制一遍查询代码。试过就知道分层不是增加工作量是给未来的自己省事。实体类的写法比较固定所有字段private提供getter/setter覆盖toString方便调试。注意日期类型的选择数据库birthday是DATE实体类里用java.util.Date还是java.sql.Date我一般用java.util.Date因为界面层处理日期时更顺手在DAO层做转换。如果你用java.time.LocalDate数据库驱动5.1.x不支持直接映射需要额外转换不建议新手一开始就用。4.2 登录校验把“密码正确”从界面事件里拆出来登录功能是检验分层是否合理的第一道考题。界面层只做两件事从文本框取值、把结果告诉用户。校验逻辑放service层public class UserService { private UserDao userDao new UserDao(); public boolean login(String username, String password) { // 常见做法先查用户再比对密码 User user userDao.findByUsername(username); if (user null) { return false; } // 实际项目不会明文存密码明文比对只用于本地课程设计 return user.getPassword().equals(password); } }登录成功后进入主界面这个“当前登录用户”的状态怎么保存新手最常见的做法是定义一个public static变量全局可访问。这在单窗口程序里没有大问题但如果你后面加了“修改本人的密码”功能就需要知道当前操作人是谁。我的做法是让主界面的构造方法接收User对象把登录用户的身份沿着调用链传下去。这样比静态变量清晰也更容易测试——你不需要登录就能构造一个带用户的主界面做UI调试。登录按钮的监听器里有一个Eclipse新手必踩的坑在事件方法里调用了DBUtil.getConnection()但数据库连的是线上库网络一抖动整个界面就卡死。这不是代码逻辑问题是异常的捕获粒度问题。Swing的事件分发线程里抛出的异常不会导致程序崩溃但会静默丢失表现就是按钮点了没反应。建议在事件方法外层用try-catch包住整个处理流程至少打一行日志否则排错时只能靠猜。4.3 学生信息增删改查主界面的表模型与按钮事件绑定主界面通常用JTable展示学生列表。JTable本身不存数据它依赖TableModel。最常见的实现是DefaultTableModel用Vector或二维数组填充。但每次增删改后都要手动刷新表模型而且JTable的单元格编辑默认是可用的如果不关掉用户双击单元格就能改显示内容但数据库里根本没变造成界面和数据库不一致。我的做法是自定义一个TableModel只读禁止编辑import javax.swing.table.AbstractTableModel; import java.util.List; public class StudentTableModel extends AbstractTableModel { private String[] columns {ID, 学号, 姓名, 性别, 出生日期, 手机号}; private ListStudent data; public StudentTableModel(ListStudent data) { this.data data; } public int getRowCount() { return data.size(); } public int getColumnCount() { return columns.length; } public Object getValueAt(int rowIndex, int columnIndex) { Student stu data.get(rowIndex); switch (columnIndex) { case 0: return stu.getId(); case 1: return stu.getStuNo(); case 2: return stu.getName(); case 3: return stu.getGender(); case 4: return stu.getBirthday(); case 5: return stu.getPhone(); default: return null; } } // 禁止单元格编辑避免界面改了数据库没改的诡异状态 public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } }按钮事件里删除操作有一个需要特别处理的问题用户选中了表格的某一行但你需要在数据库里删除的是这条记录的主键ID。TableModel的行号不等于数据库主键ID必须通过getValueAt(row, 0)取出ID再传给DAO。这个映射过程是Swing项目里最典型的“看着对但跑起来错”的场景。新增和编辑通常用一个模态对话框里面放几个文本框确定时把数据组装成Student对象调用DAO方法。保存成功后要刷新表格最简单的方式是重新查询一次列表new一个新的TableModel set到JTable上。不要试图用局部刷新学生系统数据量不大全量刷新反而省心。删除操作记得加确认弹窗JOptionPane.showConfirmDialog返回JOptionPane.YES_OPTION再执行删除。这一套走完系统基本能用了但离能答辩、能交作业还有一段路——接下来要面对的才是真正劝退新手的连环坑。5. eclipseMySQL避坑指南新手翻车最集中的五个位置5.1 eclipse找不到或无法加载主类程序明明没报编译错误现象代码没有红叉但点击Run后控制台输出“Error: 找不到或无法加载主类 com.xxx.Main”。原因这个报错在热搜里长期霸榜绝大多数情况是Eclipse的工作区缓存出了问题或者.class文件输出目录不对。常见场景是项目从别处复制过来或者用了JDK 8和JDK 11双环境后切换导致编译产物丢失。解决先Project → Clean清理所有项目让Eclipse重新编译。如果还不行右键项目 → Build Path → Configure Build Path → 检查Output folder是否指向项目下的bin目录。最后一个手段是关掉Eclipse删除工作区目录下的.metadata文件夹重新导入项目。另外有一种特殊情况Main方法不在你点击Run的类里。Eclipse的Run按钮默认运行当前编辑器里打开的类如果你开着工具类然后点Run它就会去找工具类的main方法找不到就报这个错。5.2 mysql ssl连接错误握手失败或Public Key Retrieval报错现象连接MySQL 8.0时抛出“Communications link failure”或者“Public Key Retrieval is not allowed”。原因MySQL 8.0默认认证插件是caching_sha2_password当客户端用不加密连接且需要传输密码时服务器要求先进行公钥检索。JDBC驱动5.1.x版本不认识这个流程。解决两个方向。第一个方向把连接URL加上allowPublicKeyRetrievaltrue和useSSLfalse让驱动放弃SSL直接明文传输密码检索公钥第二个方向在MySQL里把用户的认证插件改回mysql_native_password执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;然后FLUSH PRIVILEGES。这两种方案我都试过第一种改代码就行适合代码可控的课程设计第二种要额外操作数据库但能兼容更多客户端工具。5.3 中文乱码控制台、表和界面三处显示不一致现象数据库里存的是中文用Navicat for MySQL看是正常的但程序读出来是问号或乱码。或者相反程序里写进去的中文在数据库里全是乱码。原因整个链路的字符集没对齐。MySQL连接层、数据库默认字符集、Java文件的编码、Eclipse控制台的显示编码这四个环节任意一个不一致就会乱码。解决按顺序检查。第一建库时指定DEFAULT CHARACTER SET utf8这条在3.1的SQL里已经做了。第二连接URL必须带characterEncodingutf8。第三Eclipse里Windows → Preferences → General → Workspace → Text file encoding改成UTF-8。第四控制台Windows → Preferences → Run/Debug → Console的编码改成UTF-8。第五检查java文件本身如果代码里出现硬编码的中文确认.java文件保存时的编码和Eclipse工作区编码一致。MySQL 5.7的utf8字符集是utf8mb3不带emoji的常用汉字没问题如果你要存emoji或特殊符号必须用utf8mb4。5.4 MySQL安装到最后一步报错或启动即崩溃现象安装过程中卡在“Start Service”步骤或安装完成后服务无法启动错误日志里出现e0434352这类Windows错误码。原因e0434352是.NET Framework的异常MySQL安装程序的服务注册部分依赖.NET组件。多见于系统里.NET版本过旧或者之前装过MySQL没卸干净注册表残留导致服务无法注册。解决卸干净重装。控制面板卸载MySQL所有组件删除安装目录默认C:\Program Files\MySQL删除C:\ProgramData\MySQL然后regedit里搜MySQL删掉残留项。重点检查C:\Windows\System32\config\systemprofile\AppData\Local\Temp是否有MySQL临时文件。重装时以管理员身份运行安装包服务启动那一步手动选择“作为Windows服务运行”并指定本机系统账户。如果本机是Windows中文系统检查一下安装路径有没有中文安装路径含中文会导致服务注册失败。5.5 MySQL服务能连但进程占用高或连不上本地socket现象代码运行后报“Access denied for user rootlocalhost”或者命令行执行mysql -u root -p时报error 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock。原因前者是密码或host认证问题。root用户默认只允许localhost访问如果你在代码里用了127.0.0.1而授权表里只有localhost条目就可能被拒绝。后者是Linux环境下的经典问题mysql.sock文件路径不对或mysqld服务没启动。解决对Windows本地的认证问题命令行用mysql -u root -p登录后执行SELECT user, host FROM mysql.user;如果发现root只支持localhost执行ALTER USER rootlocalhost IDENTIFIED BY 你的密码;。对MySQL 5.7还可以用GRANT ALL PRIVILEGES ON *.* TO rootlocalhost IDENTIFIED BY 密码 WITH GRANT OPTION;。对Linux的socket问题确认sudo service mysql start或systemctl start mysqld是否成功然后用mysql -h 127.0.0.1 -P 3306 -u root -p绕过socket文件强制走TCP连接。这条坑在云服务器部署时特别常见本地能跑通不代表服务器上也能跑通。6. 让系统经得起拷问密码加密、分页查询与答辩前验证6.1 给密码加盐面试官问“密码怎么存”时的标准答案如果你做的系统有管理员登录功能密码直接存明文是能跑但答辩时老师一句“密码怎么防泄露”就能问住你。给密码加盐哈希在Java里代码量不大但体现的是对数据安全的意识import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class PasswordUtil { // 生成随机盐每个用户不同防止反查彩虹表 public static String generateSalt() { byte[] bytes new byte[16]; new SecureRandom().nextBytes(bytes); StringBuilder sb new StringBuilder(); for (byte b : bytes) { sb.append(String.format(%02x, b)); } return sb.toString(); } // SHA-256哈希输出64位十六进制字符串 public static String hash(String password, String salt) { try { MessageDigest md MessageDigest.getInstance(SHA-256); md.update(salt.getBytes(UTF-8)); byte[] hashed md.digest(password.getBytes(UTF-8)); StringBuilder sb new StringBuilder(); for (byte b : hashed) { sb.append(String.format(%02x, b)); } return sb.toString(); } catch (NoSuchAlgorithmException | java.io.UnsupportedEncodingException e) { e.printStackTrace(); return null; } } }登录时从数据库取出该用户的盐再对输入的密码做同样哈希后比对。存储时两个字段salt和password_hash。这里要注意一个细节哈希值比较时两个字符串都是大写或都是小写否则会因为大小写不一致导致明明密码正确却登录失败。这套方案不是最强的但它是从“零安全意识”到“知道要防”的分水岭。6.2 分页查询LIMIT参数和总条数统计的一致性学生信息管理系统数据量小但答辩时老师可能会问“几千条数据时界面卡不卡”。分页是教科书级的标准答案。MySQL的分页用LIMIT实现Java端核心是计算偏移量public ListStudent getStudentsByPage(int pageNum, int pageSize) { int offset (pageNum - 1) * pageSize; String sql SELECT id, stu_no, name, gender, birthday, phone FROM student ORDER BY id LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, offset); ps.setInt(2, pageSize); try (ResultSet rs ps.executeQuery()) { ListStudent list new ArrayList(); while (rs.next()) { Student stu new Student(); stu.setId(rs.getInt(id)); stu.setStuNo(rs.getString(stu_no)); stu.setName(rs.getString(name)); list.add(stu); } return list; } } catch (SQLException e) { e.printStackTrace(); return new ArrayList(); } } // 总页数计算不能四舍五入要用向上取整 public int getTotalPages(int pageSize) { String sql SELECT COUNT(*) FROM student; int total 0; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { if (rs.next()) { total rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); } return (int) Math.ceil((double) total / pageSize); }分页最常被忽略的两个点第一pageNum从1开始还是从0开始必须在界面层和服务层约定一致否则第二页开始数据就错位。第二COUNT(*)查询和列表查询是两条SQL在高并发下可能查出不一致的总数但学生系统这种场景可以接受不必上事务。面试问到“java怎么保证数据一致性”时可以顺势说这里如果要求严格可以用事务隔离级别或加锁但要有意识权衡。6.3 一个验收清单从启动到功能验证的完整路径答辩或交付前按这个路径走一遍能避免大多数尴尬。第一步环境验证清空Eclipse之前残留的运行配置直接右键入口类Run As Java Application确认不依赖IDE的特殊工作区配置。第二步数据库状态验证关掉Navicat等外部工具只用代码里的DBUtil连接确认连接URL里的host、port、库名没有硬编码成本地绝对路径。第三步功能回归分别测试新增、修改、删除、查询重点确认删除学生后成绩表里对应记录被级联删除——这是外键约束生效的证据。第四步异常验证在MySQL服务没启动时启动程序界面应该弹出友好错误提示而不是控制台堆栈刷屏——这一点在答辩演示时最容易暴露。我自己的习惯是最后用命令行跑一次打包右键项目 → Export → Runnable JAR File把导出的JAR放到干净目录用java -jar直接跑。能跑通说明项目不依赖Eclipse内部路径代码里的资源文件引用也都正确。这也是判断一个课程设计项目是“真做完了”还是“只在IDE里能跑”的分水岭。这个系统做完后还有一个值得做的进阶动作把三张表的关系画成ER图把每个DAO方法的SQL复杂度标出来写到项目README里。这不是形式主义是我自己吃过亏后的教训——当年答辩时老师问“为什么成绩表要单独建一张”如果没想清楚这个问题回答就会变成“因为老师这么教的”。能把建表理由、分层理由、参数设置理由讲清楚这个Java学生信息管理系统才是真正长在你身上的能力而不是存在磁盘里的一份代码。希望帮到你。本文还有配套的精品资源点击获取