Java Swing + MySQL + Eclipse 图书管理系统:从建库到能跑起来的最小闭环
简介这份资源是一套基于Java Swing、MySQL与Eclipse开发的图书管理系统完整项目源码面向正在学习Java桌面应用开发、需要完成课程设计或毕业设计的在校学生以及希望熟悉JDBC数据库编程的初学者。项目将图形界面、事件处理与数据库操作整合在一起可帮助读者理解从界面搭建到数据持久化的完整开发流程。压缩包为zip格式大小约1.58MB内含项目源码等文件配合Eclipse可直接导入运行便于对照调试与二次修改。目前已有7351人学习下载说明该案例在同类教学项目中具有较高的参考价值。读者可从中获取Swing窗口与控件布局、MySQL建表与连接、JDBC增删改查封装、图书信息与借阅管理等模块的实现思路并借助配套效果图快速把握系统整体结构适合作为入门练手与项目复盘的实践素材。1. Java Swing MySQL Eclipse 的图书管理系统从建库到能跑起来的最小闭环很多同学做课程设计时第一反应是去网上找一份图书管理系统源码下载下来发现跑不起来——数据库连不上、驱动版本对不上、Eclipse 里一堆红叉。其实这套技术栈本身并不复杂Java Swing 负责桌面端界面MySQL 存数据Eclipse 当 IDE三者拼起来就是一个完整的 C/S 架构小系统。问题往往出在环境配置和 JDBC 连接这两个环节上。这篇文章面向的是要交课程设计、要自己动手写一个能演示的图书管理系统的同学也适合想复习 JDBC Swing 的 Java 初学者。我会从建库建表开始一步步把登录、图书增删改查、借阅记录这几个核心模块串起来中间穿插我在实际调试中踩过的坑。读完你至少能拿到一个能跑、能改、能答辩的最小可用版本而不是对着别人的源码发呆。2. 环境搭建JDK、MySQL、Eclipse 三件套怎么配才不翻车2.1 JDK 与 Eclipse 的版本匹配Eclipse 本身是 Java 写的所以它依赖 JDK 运行。常见做法是装 JDK 8 或 JDK 11这两个版本对 Swing 和 JDBC 的支持最稳。JDK 17 之后 Swing 虽然还能用但部分老教程里的代码会报模块化相关的警告新手容易被吓到。安装完 JDK 后一定要配JAVA_HOME和Path。配完在命令行敲java -version javac -version两条命令输出的版本号要一致。如果java能跑但javac提示不是内部或外部命令说明Path里只加了bin没加对或者加的是 JRE 的路径。Eclipse 启动时如果报找不到 Java 虚拟机就在eclipse.ini里手动指定-vm路径指向 JDK 的bin\javaw.exe。2.2 MySQL 安装与建库建表MySQL 推荐用 5.7 或 8.0 的安装版安装时勾选MySQL Server和MySQL Workbench就够了。安装过程中会让你设 root 密码这个密码后面写 JDBC 代码要用别设完就忘。装完后用 Workbench 或命令行连上去先建库CREATE DATABASE library_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE library_db; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) NOT NULL UNIQUE, title VARCHAR(100) NOT NULL, author VARCHAR(50), publisher VARCHAR(50), total INT DEFAULT 1, available INT DEFAULT 1 ); CREATE TABLE reader ( id INT PRIMARY KEY AUTO_INCREMENT, card_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(30) NOT NULL, phone VARCHAR(20) ); CREATE TABLE borrow_record ( id INT PRIMARY KEY AUTO_INCREMENT, book_id INT, reader_id INT, borrow_date DATE, return_date DATE, status TINYINT DEFAULT 0, FOREIGN KEY (book_id) REFERENCES book(id), FOREIGN KEY (reader_id) REFERENCES reader(id) );字符集用utf8mb4是为了防止中文书名出现乱码。available字段表示当前可借数量借书时减一还书时加一这样不用每次去 count 借阅记录。外键约束建议加上能帮你提前发现数据不一致的问题但如果你在代码里删除图书时忘了先删借阅记录外键会直接报错——这是好事总比留一堆脏数据强。2.3 Eclipse 导入 MySQL 驱动MySQL 8.0 的驱动包是mysql-connector-java-8.0.x.jar5.7 用mysql-connector-java-5.1.x.jar。在 Eclipse 里右键项目 → Build Path → Configure Build Path → Libraries → Add External JARs把 jar 包加进去。加完之后在项目里写一个测试类import java.sql.Connection; import java.sql.DriverManager; public class DBTest { public static void main(String[] args) { String url jdbc:mysql://localhost:3306/library_db?useSSLfalseserverTimezoneUTCcharacterEncodingutf8; String user root; String password 你的密码; try { Class.forName(com.mysql.cj.jdbc.Driver); Connection conn DriverManager.getConnection(url, user, password); System.out.println(连接成功); conn.close(); } catch (Exception e) { e.printStackTrace(); } } }useSSLfalse是关掉 SSL 警告本地开发用不上。serverTimezoneUTC是 MySQL 8.0 必须加的不加会报The server time zone value is unrecognized。characterEncodingutf8保证中文不乱码。如果这里报ClassNotFoundException说明驱动 jar 没加对报Access denied说明用户名密码错了报Unknown database说明库名写错了或者没建库。3. Swing 界面与 JDBC 打通登录、图书管理、借阅三个模块怎么写3.1 登录窗口与用户校验登录界面用JFrameJPanelGridLayout就够了。核心是把用户名密码拿到后去数据库查public boolean login(String username, String password) { String sql SELECT * FROM admin WHERE username ? AND password ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); return rs.next(); } catch (SQLException e) { e.printStackTrace(); return false; } }用PreparedStatement而不是Statement拼接字符串一是防 SQL 注入二是避免密码里带单引号导致语法错误。DBUtil是一个工具类把DriverManager.getConnection封装成静态方法避免每个 DAO 都写一遍连接代码。登录按钮的ActionListener里拿到返回值后true就dispose()当前窗口并new MainFrame().setVisible(true)false就弹JOptionPane.showMessageDialog提示用户名或密码错误。3.2 图书管理模块的增删改查主界面用JTable展示图书列表配合DefaultTableModel动态刷新。查询全部图书public ListBook findAll() { ListBook list new ArrayList(); String sql SELECT * FROM book; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setIsbn(rs.getString(isbn)); b.setTitle(rs.getString(title)); b.setAuthor(rs.getString(author)); b.setAvailable(rs.getInt(available)); list.add(b); } } catch (SQLException e) { e.printStackTrace(); } return list; }新增图书时除了插入book表还要注意total和available的初始值要一致。修改图书时如果改了totalavailable也要同步调整否则会出现总数 5 本可借 7 本这种玄学数据。删除图书前先检查borrow_record里有没有未归还的记录有就提示该图书有未归还记录不能删除。表格刷新用tableModel.setRowCount(0)清空再重新addRow比直接fireTableDataChanged更直观不容易出现残影。3.3 借阅与归还的事务处理借书操作涉及两张表borrow_record插入一条记录book表的available减一。这两步必须在一个事务里public boolean borrowBook(int bookId, int readerId) { String checkSql SELECT available FROM book WHERE id ? FOR UPDATE; String insertSql INSERT INTO borrow_record(book_id, reader_id, borrow_date, status) VALUES(?, ?, CURDATE(), 0); String updateSql UPDATE book SET available available - 1 WHERE id ? AND available 0; Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); try (PreparedStatement check conn.prepareStatement(checkSql)) { check.setInt(1, bookId); ResultSet rs check.executeQuery(); if (!rs.next() || rs.getInt(available) 0) { conn.rollback(); return false; } } try (PreparedStatement ins conn.prepareStatement(insertSql); PreparedStatement upd conn.prepareStatement(updateSql)) { ins.setInt(1, bookId); ins.setInt(2, readerId); ins.executeUpdate(); upd.setInt(1, bookId); int rows upd.executeUpdate(); if (rows 0) { conn.rollback(); return false; } } conn.commit(); return true; } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { if (conn ! null) try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }FOR UPDATE是行级锁防止两个人同时借最后一本书时都查到available1然后都减成功。UPDATE语句里带AND available 0是第二道保险即使锁没生效也不会把库存减成负数。还书就是反过来更新borrow_record的return_date和status再把available加一。4. 避坑与排查图书管理系统开发中最容易翻车的 5 个点4.1 中文乱码数据库、连接、界面三处都要查现象图书标题在 Swing 表格里显示成???或者方块。原因通常是数据库字符集不是utf8mb4或者 JDBC URL 没加characterEncodingutf8。解决建库时指定DEFAULT CHARACTER SET utf8mb4URL 里加characterEncodingutf8Eclipse 项目的编码也设成 UTF-8右键项目 → Properties → Resource → Text file encoding。4.2 驱动加载失败ClassNotFoundException现象运行时报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因是 jar 包没加到 Build Path或者 MySQL 5.7 用了 8.0 的驱动类名。解决确认 jar 在 Libraries 里5.7 用com.mysql.jdbc.Driver8.0 用com.mysql.cj.jdbc.Driver。4.3 时区报错serverTimezone 必须加现象MySQL 8.0 连接时报The server time zone value ?D1ú±ê×?ê±?? is unrecognized。原因是 MySQL 8.0 默认时区和 JDBC 驱动不匹配。解决URL 里加serverTimezoneUTC或serverTimezoneAsia/Shanghai。4.4 外键约束导致删除失败现象删除图书时抛Cannot delete or update a parent row: a foreign key constraint fails。原因是borrow_record里有该图书的记录。解决先删借阅记录再删图书或者把外键改成ON DELETE CASCADE但这样会丢历史数据不推荐。4.5 Swing 界面卡死数据库操作别放 EDT现象点击查询按钮后界面卡住不动直到数据返回。原因是数据库操作写在了ActionListener里而ActionListener运行在事件调度线程EDT上。解决用SwingWorker把数据库操作放到后台线程done()方法里再更新表格。5. 进阶技巧用 DAO 分层和连接池让代码能拿去答辩5.1 把 JDBC 代码抽成 DAO 层新手最容易犯的错是把所有 SQL 写在按钮的ActionListener里一个类几百行改一个字段要翻半天。常见做法是分三层entity放实体类dao放数据库操作ui放界面。BookDao里只写findAll、insert、update、deleteBookPanel里只负责调 DAO 和刷新表格。这样答辩时老师问你的业务逻辑在哪你能直接指出来。5.2 用连接池替代每次新建连接DriverManager.getConnection每次都会新建物理连接频繁操作时性能很差。可以引入HikariCP或Druid在DBUtil静态块里初始化DataSourceprivate static HikariDataSource ds; static { HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/library_db?useSSLfalseserverTimezoneUTCcharacterEncodingutf8); config.setUsername(root); config.setPassword(你的密码); config.setMaximumPoolSize(10); ds new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return ds.getConnection(); }连接池的maximumPoolSize设 10 就够桌面应用用了设太大反而浪费资源。用连接池后close()不再是关闭物理连接而是归还到池里所以 DAO 里的 try-with-resources 写法不用改。5.3 答辩演示前必做的三个检查第一把数据库脚本导出成.sql文件换台电脑能直接导入。第二把password改成从配置文件读别硬编码在代码里演示时老师看到硬编码密码会扣分。第三准备两条测试数据一条正常借阅、一条库存为零时借阅演示时能体现事务回滚的效果。我自己第一次做课程设计时因为没加serverTimezone在机房电脑上死活连不上数据库最后发现是 MySQL 版本和驱动不匹配。后来养成的习惯是每换一个环境先跑一遍DBTest确认连接通了再写业务代码。希望帮到你。本文还有配套的精品资源点击获取