
简介这份资源是面向高校Java与大数据课程期末实践的银行管理系统完整工程基于Eclipse开发、MySQL作为后台数据库适合正在做课程设计或需要巩固JDBC与控制台编程的初学者与中级学习者。压缩包共14个文件约2.25MB包含4个java源码、5个class编译文件、1个mysql-connector驱动jar以及project、classpath、prefs等Eclipse工程配置导入后可直接运行调试。系统围绕管理员与顾客两类角色展开管理员可登录、添加与删除顾客、统计存储金额、查看富豪排行榜顾客可登录、存款、取款、转账与修改密码覆盖了数据库连接、增删改查、事务处理与菜单交互等核心知识点。目前已有418人学习下载可作为期末大作业的参考实现帮助读者快速理清项目结构、理解业务逻辑与排错思路。1. 银行管理系统期末项目从建表到跑通EclipseMySQL 这套组合到底能扛多少活如果你正在搜「Java 大数据期末 银行管理系统 eclipse项目 MySQL数据库」大概率是三种处境之一期末大作业下周要交、课程设计想找个能跑通的参考、或者自学 Java 想拿一个完整项目练手。我当年第一次做这个题的时候以为最麻烦的是写代码结果真正卡住我的是 MySQL 8 的驱动包没放进 lib 目录、Eclipse 的 Build Path 没配对、以及事务提交忘了关连接导致数据对不上。银行管理系统这个题目看起来简单——开户、存款、取款、转账、查流水——但它几乎把 Java 基础、JDBC、Swing 界面、数据库事务这几块全串起来了是一个非常适合用来检验「面向对象编程 Java」到底学没学明白的载体。这篇文章不讲空话直接按我实际做过的路径把建库建表、DAO 封装、Swing 界面、事务控制和 Eclipse 环境配置一步步拆开让你能照着复现也知道哪里容易翻车。2. 先想清楚数据模型银行管理系统的表结构怎么设计才不返工2.1 四张核心表撑起整个系统银行管理系统的数据模型不复杂但设计时如果偷懒后面写转账逻辑会非常痛苦。我一般会建四张表账户表、交易流水表、用户表、管理员表。账户表存余额和账户状态交易流水表存每一笔操作记录用户表存登录信息管理员表存后台权限。这里最关键的是账户表和流水表的关系——每一笔转账必须同时写两条流水转出方一条、转入方一条并且和账户余额的更新在同一个事务里。-- 创建数据库字符集用 utf8mb4避免中文乱码 CREATE DATABASE bank_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE bank_system; -- 账户表卡号做主键余额用 DECIMAL 保证精度 CREATE TABLE account ( card_no VARCHAR(19) PRIMARY KEY COMMENT 银行卡号, user_id INT NOT NULL COMMENT 关联用户ID, balance DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 账户余额, status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0冻结, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user (user_id) ) ENGINEInnoDB; -- 交易流水表记录每一笔资金变动 CREATE TABLE trans_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, card_no VARCHAR(19) NOT NULL, trans_type VARCHAR(10) NOT NULL COMMENT DEPOSIT/WITHDRAW/TRANSFER_OUT/TRANSFER_IN, amount DECIMAL(15,2) NOT NULL, balance_after DECIMAL(15,2) NOT NULL COMMENT 交易后余额, target_card VARCHAR(19) DEFAULT NULL COMMENT 转账对方卡号, trans_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_card_time (card_no, trans_time) ) ENGINEInnoDB; -- 用户表 CREATE TABLE user_info ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL COMMENT 存SHA-256摘要不存明文, real_name VARCHAR(50), id_card VARCHAR(18), phone VARCHAR(11) ) ENGINEInnoDB;建表时有两个参数必须注意。第一余额字段用DECIMAL(15,2)而不是FLOAT或DOUBLE浮点数在金额计算上会出现0.10.20.30000000000000004这种玄学问题期末演示时如果被老师看到余额对不上解释起来很尴尬。第二存储引擎必须用InnoDB因为只有 InnoDB 支持事务转账的原子性全靠它。MySQL 8.4 默认就是 InnoDB但如果你从旧版本迁移或者手动改过配置建表时显式写上更保险。2.2 转账场景为什么必须用事务转账是银行管理系统里唯一一个「要么全成功、要么全回滚」的操作。假设 A 向 B 转 500 元逻辑上要做四件事扣 A 的余额、写 A 的转出流水、加 B 的余额、写 B 的转入流水。如果扣完 A 的钱、程序崩了B 没收到这 500 块就凭空消失了。所以这四步必须包在一个事务里。// 转账核心逻辑手动控制事务任何一步失败全部回滚 public boolean transfer(String fromCard, String toCard, BigDecimal amount) { Connection conn null; PreparedStatement ps null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交开启事务 // 1. 检查转出账户余额是否充足加行锁防止并发扣款 String checkSql SELECT balance FROM account WHERE card_no? AND status1 FOR UPDATE; ps conn.prepareStatement(checkSql); ps.setString(1, fromCard); ResultSet rs ps.executeQuery(); if (!rs.next()) throw new RuntimeException(账户不存在或已冻结); BigDecimal balance rs.getBigDecimal(balance); if (balance.compareTo(amount) 0) throw new RuntimeException(余额不足); // 2. 扣转出方余额 ps conn.prepareStatement(UPDATE account SET balancebalance-? WHERE card_no?); ps.setBigDecimal(1, amount); ps.setString(2, fromCard); ps.executeUpdate(); // 3. 加转入方余额 ps conn.prepareStatement(UPDATE account SET balancebalance? WHERE card_no?); ps.setBigDecimal(1, amount); ps.setString(2, toCard); if (ps.executeUpdate() 0) throw new RuntimeException(对方账户不存在); // 4. 写两条流水 insertLog(conn, fromCard, TRANSFER_OUT, amount, toCard); insertLog(conn, toCard, TRANSFER_IN, amount, fromCard); conn.commit(); // 全部成功才提交 return true; } catch (Exception e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { DBUtil.close(conn, ps, null); // 连接必须归还否则连接池很快耗尽 } }这段代码里有三个容易被忽略的点。FOR UPDATE是行级锁防止两个人同时从同一个账户扣钱导致余额变成负数这是并发场景下的后悔药。setAutoCommit(false)之后如果忘了commit()数据不会落库期末演示时你会看到「转账成功」但刷新后余额没变。finally块里的close必须执行否则连接泄漏跑几十次操作后数据库就拒绝新连接了。3. Eclipse 里把 JDBC 跑通驱动、连接池和 Build Path 三件事3.1 MySQL 8 的驱动包怎么放才不报 ClassNotFoundEclipse 项目跑 JDBC 最常见的翻车现场就是java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因通常有两个一是没下载驱动 jar 包二是下载了但没加到 Build Path。MySQL 8 之后的驱动类名从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver如果你抄的是老教程的代码类名对不上也会报错。操作步骤很固定去 MySQL 官网下载mysql-connector-j-8.x.x.jar在 Eclipse 项目根目录新建lib文件夹把 jar 包复制进去然后右键项目 → Build Path → Configure Build Path → Libraries → Add JARs选中 lib 里的 jar。做完这一步项目结构里会出现Referenced Libraries里面能看到驱动包。// DBUtil统一管理连接避免每次手写 DriverManager public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/bank_system?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PWD 你的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); // MySQL 8 的驱动类名 } catch (ClassNotFoundException e) { throw new RuntimeException(驱动加载失败检查 jar 是否加入 Build Path, e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } public static void close(Connection c, Statement s, ResultSet r) { try { if (r ! null) r.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (s ! null) s.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (c ! null) c.close(); } catch (SQLException e) { e.printStackTrace(); } } }连接 URL 里的serverTimezoneAsia/Shanghai必须加否则 MySQL 8 会报时区错误这个坑我见过太多人踩。useSSLfalse在本地开发时加上避免控制台一直刷 SSL 警告。characterEncodingutf8保证中文姓名和备注不乱码。3.2 要不要上连接池期末项目的取舍热搜里有人问「mysql 的数据库连接池」我的建议是期末项目如果只是单机演示DriverManager直接拿连接完全够用代码简单、调试直观。但如果你想在答辩时体现一点工程思维可以引入 Druid 或 HikariCP。连接池的核心价值是复用连接避免每次操作都经历 TCP 三次握手和权限校验。// 用 HikariCP 替换 DriverManager 的写法配置文件放 src 下 HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/bank_system?useSSLfalseserverTimezoneAsia/Shanghai); config.setUsername(root); config.setPassword(你的密码); config.setMaximumPoolSize(10); // 最大连接数期末演示 10 足够 config.setMinimumIdle(2); // 最小空闲连接 config.setConnectionTimeout(3000); // 获取连接超时 3 秒 HikariDataSource ds new HikariDataSource(config); // 之后用 ds.getConnection() 替代 DriverManager.getConnection()参数上maximumPoolSize不要设太大本地 MySQL 默认最大连接数是 151设 10 到 20 之间比较稳妥。connectionTimeout设 3000 毫秒这样连接池耗尽时能快速失败而不是卡死界面。如果你用 Druid配置项名字不同但逻辑一样按官方示例改即可。4. Swing 界面与 DAO 分层让代码能讲清楚而不是一坨4.1 三层结构界面、业务、数据各管各的很多期末项目把所有逻辑塞进一个MainFrame类几千行代码老师一问「你的业务逻辑在哪」就答不上来。我一般分成三层ui包放 Swing 窗口和事件监听service包放转账、开户这些业务方法dao包只负责 SQL 执行。这样做的直接好处是转账的事务控制放在 service 层dao 层只提供updateBalance、insertLog这种原子方法职责清晰。// AccountDao只做数据访问不掺业务判断 public class AccountDao { public BigDecimal queryBalance(String cardNo) throws SQLException { String sql SELECT balance FROM account WHERE card_no?; try (Connection c DBUtil.getConnection(); PreparedStatement ps c.prepareStatement(sql)) { ps.setString(1, cardNo); try (ResultSet rs ps.executeQuery()) { return rs.next() ? rs.getBigDecimal(balance) : null; } } } public int updateBalance(Connection c, String cardNo, BigDecimal delta) throws SQLException { String sql UPDATE account SET balancebalance? WHERE card_no?; try (PreparedStatement ps c.prepareStatement(sql)) { ps.setBigDecimal(1, delta); ps.setString(2, cardNo); return ps.executeUpdate(); } } }注意updateBalance接收一个外部传入的Connection而不是自己从DBUtil拿。这是为了让 service 层能把多个 dao 操作绑在同一个事务里。如果 dao 自己管连接事务就没法跨方法控制了。这个设计点答辩时能讲出来加分不少。4.2 Swing 事件线程别做耗时操作Swing 有个经典坑在按钮的actionPerformed里直接查数据库如果查询慢界面会假死。正确做法是把数据库操作放到SwingWorker的doInBackground里结果通过done方法回传更新界面。// 查询流水按钮的事件处理用 SwingWorker 避免界面卡死 queryBtn.addActionListener(e - { String cardNo cardField.getText().trim(); new SwingWorkerListTransLog, Void() { Override protected ListTransLog doInBackground() throws Exception { return transLogDao.queryByCard(cardNo); // 后台线程查数据库 } Override protected void done() { try { ListTransLog list get(); // 更新 JTable 模型必须在 EDT 线程做 tableModel.setData(list); } catch (Exception ex) { JOptionPane.showMessageDialog(null, 查询失败 ex.getMessage()); } } }.execute(); });doInBackground在后台线程跑done回到事件分发线程EDT这样界面不会卡。期末演示时如果数据量小可能感觉不到差别但老师如果问「并发怎么办」这就是一个能展开讲的点。5. 避坑与排查银行管理系统最容易翻车的五个地方5.1 中文乱码从数据库到界面全链路排查现象存入「张三」后查出来是「??」或者「å¼ ä¸」。原因通常是三个环节的字符集不一致数据库建库时没指定utf8mb4、连接 URL 没加characterEncodingutf8、Eclipse 工作空间编码不是 UTF-8。解决方法是逐层确认SHOW VARIABLES LIKE character%看数据库字符集连接 URL 补上编码参数Eclipse 里 Window → Preferences → General → Workspace 把 Text file encoding 改成 UTF-8。5.2 余额精度丢失用 double 算钱的代价现象存 100.1 再存 100.2查出来是 200.29999999999998。原因是用double或float做金额运算。解决方法是数据库用DECIMALJava 侧用BigDecimal并且BigDecimal比较大小要用compareTo而不是equals因为equals会比较精度1.0和1.00不相等。5.3 连接泄漏跑几十次后数据库拒绝连接现象程序运行一段时间后报Too many connections。原因是每次操作都DriverManager.getConnection()但没在finally里关闭。解决方法是统一用DBUtil.close()在finally块关闭或者改用连接池自动管理。检查方法是登录 MySQL 执行SHOW PROCESSLIST看有没有大量 Sleep 状态的连接堆积。5.4 事务没生效转账一半成功一半失败现象A 扣了钱B 没收到流水只写了一条。原因是setAutoCommit(false)之后某一步抛异常但没rollback或者用了 MyISAM 引擎不支持事务。解决方法是确认表引擎是 InnoDB在catch块里显式rollback并且把commit放在所有操作成功之后。5.5 Eclipse 找不到主类Build Path 和输出目录错位现象右键 Run As → Java Application 报「找不到或无法加载主类」。原因通常是src文件夹不在 Build Path 里或者bin输出目录被误删。解决方法是右键项目 → Build Path → Configure Build Path → Source确认src在列表里且 Output folder 指向bin。如果还不行Project → Clean 重新编译一次。6. 让项目从「能跑」到「能讲」三个进阶技巧和我的习惯第一个技巧是给关键操作加日志。不用上 Log4j 那么重自己写一个简单的LogUtil把每次转账的卡号、金额、时间追加写到文件里。答辩时老师问「你怎么追踪一笔交易」你打开日志文件指给他看比口头解释有说服力。// 极简日志工具追加写入不依赖第三方库 public class LogUtil { private static final String LOG_FILE bank_operation.log; public static void write(String action, String cardNo, String detail) { String line String.format([%s] %s | %s | %s%n, new SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(new Date()), action, cardNo, detail); try (FileWriter fw new FileWriter(LOG_FILE, true)) { // true 表示追加 fw.write(line); } catch (IOException e) { e.printStackTrace(); } } }第二个技巧是给账户表加一个版本号字段做乐观锁。虽然期末项目并发量几乎为零但如果你在报告里写「考虑到并发场景采用版本号机制避免超扣」这就是一个超出预期的亮点。实现方式是在account表加version INT DEFAULT 0更新时UPDATE account SET balancebalance-?, versionversion1 WHERE card_no? AND version?如果返回影响行数为 0 说明有人抢先改了重试或提示用户。第三个技巧是准备一份「异常演示脚本」。答辩时老师很可能让你现场演示转账失败的情况你可以提前准备一个余额不足的账户演示时故意转一笔超额的钱让系统弹出「余额不足」提示然后打开流水表证明没有产生脏数据。这个流程走下来比你说一百句「我做了事务控制」都管用。我自己做这类项目的习惯是先把数据库建好、插几条测试数据然后用一个最简单的main方法跑通 JDBC 查询确认驱动和连接没问题再去写 Swing 界面。很多人反过来界面画了半天结果连不上数据库排查起来心态容易崩。另外Eclipse 的 Console 报错要逐行看尤其是Caused by那几行真正的根因往往在最后。希望帮到你。本文还有配套的精品资源点击获取