首页 / 资讯中心 / 文章详情

Java Swing + MySQL 银行管理系统实战:从环境搭建到事务处理

Java Swing + MySQL 银行管理系统实战:从环境搭建到事务处理 ★ FEATURED ARTICLE
简介这是一套面向Java初学者与课程设计学习者的银行管理系统项目源码基于IntelliJ IDEA开发采用Java Swing构建图形界面以MySQL作为后台数据存储实现管理员与顾客两类角色的完整业务闭环。管理员可登录、添加或删除顾客、统计存储金额顾客可完成登录、存款、取款、转账、修改密码、查看交易记录及安全退出等操作适合作为Java面向对象编程、数据库应用与Swing界面开发的综合练习素材。资源包为rar压缩格式共28个文件约40KB其中包含14个class编译文件、6个xml与2个yml配置、2个html页面、1个java源码及说明文档覆盖项目配置、源码与构建产物等模块。目前已有424人学习浏览。通过该资源读者可对照完整目录结构理解分层设计与数据库交互思路掌握JDBC操作、事务处理与界面事件绑定等关键技能并在此基础上进行功能扩展与二次开发。1. 从一份能跑起来的 Java 银行管理系统说起IDEA Swing MySQL 的完整落地路径很多人学 Java 学到集合和 IO 就卡住了不知道下一步该拿什么练手。网上搜「Java 项目实战」跳出来的不是 Spring Boot 商城就是秒杀系统环境还没配完就劝退了。这份 CampusBankSys 走的是另一条路不依赖任何 Web 框架用 JavaSwing 做界面、MySQL 做数据存储、IntelliJ IDEA 做开发环境把银行管理里最核心的几件事——管理员登录、顾客增删、存取款、转账、改密码、交易记录查询——全部用原生 Java 实现了一遍。它适合刚学完 Java 基础、想找一个能完整跑通的项目来理解「分层」和「数据库交互」的人也适合当课程设计或毕业设计的底稿。下面按「拿到手怎么跑 → 代码怎么组织 → 坑在哪 → 怎么改」的顺序拆一遍。2. 环境搭建与项目导入从解压到第一次成功运行2.1 JDK、MySQL、IDEA 三件套的版本对齐这个项目用的是原生 JavaSwing没有 Maven 之外的框架依赖所以环境要求不算苛刻但版本对不齐照样跑不起来。我一般会先确认三件事JDK 版本、MySQL 版本、IDEA 的编译输出级别。JDK 建议用 8 或 11。项目里如果用了var或者List.of()这类语法就必须 11 以上如果全是传统写法8 也能跑。判断方法很简单打开pom.xml看maven.compiler.source和maven.compiler.target两个标签的值它们写的是几你的 JDK 就不能低于几。MySQL 用 5.7 或 8.0 都行但要注意驱动包的区别。5.7 用com.mysql.jdbc.Driver8.0 用com.mysql.cj.jdbc.Driver而且 8.0 的连接串必须带时区和 SSL 参数否则控制台会甩一堆红色警告。这个项目正文里没有明确写死版本所以拿到手第一件事就是看pom.xml里mysql-connector-java的版本号再决定用哪个驱动类名。IDEA 这边社区版就够用不需要 Ultimate。导入时选「Open」而不是「New Project」直接定位到解压后含pom.xml的那一层目录。导入后等 Maven 索引跑完如果右下角弹出「Maven projects need to be imported」点 Enable Auto-Import。2.2 数据库建库建表与连接配置项目跑不起来十有八九是数据库没建对。CampusBankSys 的src目录下通常会有一个.sql文件或者HELP.md里附了建表语句。如果都没有就按业务反推至少需要一张用户表存管理员和顾客、一张交易记录表。常见做法是建一个名为bank或campusbank的库字符集用utf8mb4排序规则utf8mb4_general_ci。建库语句如下CREATE DATABASE IF NOT EXISTS campusbank DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;然后建用户表字段至少包含主键 id、用户名、密码、角色区分管理员和顾客、余额、创建时间。交易记录表包含主键 id、关联用户 id、交易类型存款/取款/转账、金额、交易时间、备注。USE campusbank; CREATE TABLE IF NOT EXISTS t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, role TINYINT NOT NULL DEFAULT 0 COMMENT 0-顾客 1-管理员, balance DECIMAL(12,2) NOT NULL DEFAULT 0.00, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS t_transaction ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, type VARCHAR(20) NOT NULL COMMENT DEPOSIT/WITHDRAW/TRANSFER, amount DECIMAL(12,2) NOT NULL, trade_time DATETIME DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(255), INDEX idx_user_id (user_id) );建完表回到 IDEA 里找数据库连接配置。这类项目通常把 JDBC 参数写在一个db.properties或者直接硬编码在某个DBUtil类里。搜索关键词jdbc:mysql就能定位。连接串的格式要注意jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/campusbank?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password你的密码serverTimezone这个参数在 MySQL 8.0 下必须加否则会报The server time zone value ... is unrecognized。useSSLfalse是为了避免本地开发时的 SSL 握手警告。这两个参数是新手最容易漏的漏了就连接失败。2.3 在 IDEA 中运行主类与常见启动报错配置改完后找到含main方法的启动类。Swing 项目的入口类名通常叫Main、App或LoginFrame在src/main/java下按包名逐层找。右键 → Run。如果报ClassNotFoundException: com.mysql.cj.jdbc.Driver说明 Maven 依赖没下载成功去 IDEA 右侧 Maven 面板点一下刷新或者检查pom.xml里mysql-connector-java的scope是不是被写成了provided。如果报Access denied for user rootlocalhost就是密码不对改db.properties里的jdbc.password。如果界面弹出来了但点登录没反应先看控制台有没有异常堆栈。Swing 的事件处理是在 EDT 线程里跑的异常不会弹窗只会打到控制台。这是 Swing 开发和 Web 开发最大的体感差异——Web 报错浏览器能看到Swing 报错得盯着 IDEA 的 Console。3. 代码结构拆解Swing 界面层、业务逻辑层与 JDBC 数据层的分工3.1 包结构与分层逻辑拿到一个陌生 Java 项目我习惯先看包名。CampusBankSys 的src/main/java下通常会有这么几层com.xxx.entity或model实体类对应数据库表比如User、Transaction。com.xxx.dao或dal数据访问层封装 JDBC 的增删改查。com.xxx.service或biz业务逻辑层处理转账时扣款加款这种需要事务的操作。com.xxx.ui或viewSwing 界面类负责画窗口、按钮、表格。com.xxx.util工具类比如DBUtil管理连接。这个分层不是摆设。银行系统里转账操作必须保证「A 扣钱」和「B 加钱」在同一个事务里要么都成功要么都回滚。如果所有逻辑都写在按钮的actionPerformed里事务根本没法控制。所以看到service层里有Connection的setAutoCommit(false)和commit()说明作者是认真考虑过业务完整性的。3.2 管理员功能登录验证与顾客增删的实现要点管理员登录的流程是Swing 界面拿到用户名密码 → 调service.login()→dao层查t_user表 → 比对密码和角色 → 返回结果。这里有个常见做法是把密码做一次 MD5 或 SHA-256 再存库但很多教学项目为了简单是明文存的。如果你要改成加密注意登录时也要用同样的算法加密后再比对。添加顾客的代码逻辑大致如下// service 层添加顾客 public boolean addCustomer(String username, String password) { // 先检查用户名是否已存在 if (userDao.findByUsername(username) ! null) { return false; // 用户名重复 } User user new User(); user.setUsername(username); user.setPassword(password); // 生产环境应加密 user.setRole(0); // 0 表示顾客 user.setBalance(BigDecimal.ZERO); return userDao.insert(user) 0; }role字段是区分管理员和顾客的关键。管理员登录时role1顾客登录时role0。如果登录时不校验角色顾客账号也能进管理界面这是个权限漏洞。删除顾客同理调dao.deleteById()但要注意如果该顾客还有交易记录直接删用户会导致交易记录表出现孤儿数据。常见做法是先删交易记录再删用户或者用软删除加一个is_deleted字段。计算存储金额这个功能本质就是SELECT SUM(balance) FROM t_user WHERE role0在dao层用一个聚合查询搞定返回BigDecimal而不是double避免浮点精度问题。3.3 顾客功能存款、取款、转账与交易记录的事务处理顾客端的核心是转账。存款和取款只涉及单条记录的更新转账涉及两条更新加一条记录插入必须放在一个事务里。// service 层转账 public boolean transfer(int fromUserId, int toUserId, BigDecimal amount) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 扣款方余额减少 int rows1 userDao.updateBalance(conn, fromUserId, amount.negate()); // 2. 收款方余额增加 int rows2 userDao.updateBalance(conn, toUserId, amount); // 3. 插入交易记录 int rows3 transactionDao.insert(conn, fromUserId, TRANSFER, amount, 转给用户 toUserId); if (rows1 0 rows2 0 rows3 0) { conn.commit(); return true; } else { conn.rollback(); return false; } } catch (SQLException e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { DBUtil.close(conn); } }这里的关键点是dao层的方法要接收外部传入的Connection而不是自己内部去getConnection()。否则每个dao方法拿到的都是不同的连接事务根本控制不住。这是 JDBC 事务管理最容易翻车的地方。交易记录查询就是按user_id查t_transaction表按trade_time倒序排列在 Swing 里用JTable展示。JTable的数据模型用DefaultTableModel把查询结果一行行addRow进去就行。修改密码的逻辑是验证旧密码 → 更新新密码。注意更新后要提示用户重新登录否则当前会话里的密码状态和数据库不一致。4. 避坑与排查数据库连接、Swing 线程和中文乱码的常见问题4.1 连接池未关闭导致 MySQL 连接数耗尽现象程序运行一段时间后所有数据库操作都卡住MySQL 报Too many connections。原因每次dao操作都new一个Connection用完没有close()。MySQL 默认最大连接数是 151教学项目里循环查几次就耗光了。解决在DBUtil里统一管理连接每个dao方法的finally块里必须close()。更好的做法是引入 Druid 或 HikariCP 连接池但教学项目用try-with-resources就够了try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { // 执行操作 } catch (SQLException e) { e.printStackTrace(); }4.2 Swing 事件在 EDT 线程外更新界面导致卡死现象点击按钮后界面卡住不动或者表格数据更新了但界面没刷新。原因Swing 不是线程安全的所有界面更新必须在事件调度线程EDT里执行。如果在后台线程里直接调tableModel.addRow()就会出现玄学问题——有时候正常有时候卡死。解决用SwingUtilities.invokeLater()包裹界面更新代码SwingUtilities.invokeLater(() - { tableModel.addRow(new Object[]{...}); });如果数据库查询耗时较长应该把查询放在SwingWorker的doInBackground()里在done()里更新界面。4.3 中文乱码数据库、连接串、IDEA 三处编码不一致现象存进去的中文变成???或者界面显示乱码。原因三个地方的编码没有统一——MySQL 建库时的字符集、JDBC 连接串里的characterEncoding、IDEA 的文件编码。解决建库用utf8mb4连接串加characterEncodingutf8IDEA 设置里 File Encodings 全部改成 UTF-8。三处缺一不可。如果已经存了乱码数据改完编码后需要重新录入。4.4 转账金额用 double 导致精度丢失现象转账 0.1 元加 0.2 元余额显示 0.30000000000000004。原因double和float是浮点数无法精确表示十进制小数。银行系统里这是致命问题。解决金额字段在 Java 里用BigDecimal在 MySQL 里用DECIMAL(12,2)。BigDecimal的加减用add()和subtract()不要用和-。构造BigDecimal时用字符串构造器new BigDecimal(0.1)不要用new BigDecimal(0.1)。4.5 删除顾客时外键约束报错现象删除顾客时报Cannot delete or update a parent row: a foreign key constraint fails。原因t_transaction表里有该顾客的交易记录外键约束阻止删除。解决两种方案——先删交易记录再删用户或者建表时把外键设为ON DELETE CASCADE。教学项目里更推荐前者因为交易记录通常需要保留审计。如果业务上允许级联删除就在建表语句里加FOREIGN KEY (user_id) REFERENCES t_user(id) ON DELETE CASCADE。5. 从能跑到能改二次开发与功能扩展的实操建议把项目跑起来只是第一步真正让这份资源产生价值的是在它基础上改出自己想要的东西。我一般会从三个方向动手加功能、换存储、改界面。加功能方面最值得做的是把明文密码改成加密存储。在service层的注册和登录方法里各加一次MessageDigest调用就行public static String sha256(String input) throws NoSuchAlgorithmException { MessageDigest md MessageDigest.getInstance(SHA-256); byte[] digest md.digest(input.getBytes(StandardCharsets.UTF_8)); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); }登录时把用户输入的密码做一次sha256再和数据库里的哈希比对。注意数据库里存的也要是哈希值所以已有的明文密码需要批量更新一次。换存储方面如果想把 JDBC 换成 MyBatis 或 MyBatis-Plus核心改动在dao层。pom.xml里加依赖写mapper接口和 XML 映射文件service层的调用方式基本不变。MyBatis-Plus 的好处是单表增删改查不用写 SQLBaseMapper里直接有insert、deleteById、selectList。但转账这种跨表事务操作还是得手写 SQL 或者用Transactional注解。改界面方面Swing 的JFrame、JPanel、JTable组合可以做出还不错的布局。如果想换成 JavaFX界面代码要全部重写但service和dao层可以原样保留。这也是分层架构的好处——换界面不影响业务逻辑。验证改动是否成功我习惯用一个小清单过一遍管理员能登录吗添加顾客后数据库里有记录吗顾客登录后余额显示正确吗存款 100 后余额变了吗转账后两边余额都对吗交易记录能查到吗改密码后用新密码能登录吗这七个问题全过基本就没大问题了。从那以后我每次拿到一个教学项目都强制自己先跑通再改一个功能因为只有改过才知道自己是不是真的看懂了。希望这份拆解能帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站