Java Swing + MySQL 运动会管理系统:从建库到排名并列的完整实现

发布时间:2026/10/5 11:16:25
Java Swing + MySQL 运动会管理系统:从建库到排名并列的完整实现 简介这份资源是一套基于Java Swing与MySQL开发的田径运动会管理系统面向计算机相关专业学生、课程设计者及Java初学者可用于数据库课设、Swing桌面应用练手或作为完整项目参考。系统围绕运动员、参赛团体、比赛安排与裁判信息展开支持按编号或姓名模糊查询并能统计团体金牌数、关联查询运动员个人信息与上轮成绩录入全能赛成绩后自动计算总分并排序同时对数据合法性、查询无结果及数据库连接异常给出提示。压缩包共74个文件约2.2MB包含12个java源码、48个class文件、5个xml配置、1个sql建库脚本以及docx课程报告另附jar依赖与项目配置文件结构完整可直接导入IDEA或Eclipse配合MySQL5.7以上运行。目前已有188人学习适合需要完整赛题方案、数据库设计思路与Swing界面实现细节的读者参考借鉴。1. 运动会管理系统为什么还在用 Java Swing 做客户端每年校运会、企业运动会前后总有人被安排做一套报名、编排、计分、成绩公示的系统。预算不多、时间很紧、部署环境还经常是机房里的老 Windows 机器这时候 Java Swing MySQL 这套组合反而比一堆前端框架更省事一个可执行 jar 双击就能跑不用装浏览器兼容层不用配 Node 环境数据库装好导入 SQL 就能用。这个标题里的「运动会管理系统」本质是一套典型的 CRUD 统计报表 权限分级的桌面应用核心难点不在界面炫不炫而在报名人数上限校验、项目冲突检测、成绩排名并列处理、以及课程报告里要讲清楚的三层架构。它适合课程设计、毕业设计、小型单位内部工具三类人新手能照着把功能跑通熟手能借它练手事务和并发。下面按「先跑通、再讲透、最后避坑」的顺序拆开讲。2. 环境搭建与数据库设计从建库到能连上2.1 JDK、MySQL 与驱动版本怎么选这套系统对版本不敏感但踩坑最多的恰恰是版本。JDK 用 8 或 11 都行Swing 在 11 之后没有破坏性改动但如果你用 JDK 17 编译、又拿 JDK 8 去跑会报 UnsupportedClassVersionError。MySQL 建议 5.7 或 8.0两者在驱动类名和连接串上有区别这是新手第一个翻车点。组件推荐版本说明JDK8 / 118 兼容性最好11 是长期支持MySQL5.7.44 或 8.0.x5.7 稳定8.0 默认字符集更省心驱动 jarmysql-connector-java 5.1.x配5.7/ 8.0.x配8.0版本必须和数据库大版本对应IDEIntelliJ IDEA 或 Eclipse需要能直接加外部 jar驱动版本对不上典型现象是Loading class com.mysql.jdbc.Driver. This is deprecated或者直接No suitable driver found。5.7 用com.mysql.jdbc.Driver8.0 用com.mysql.cj.jdbc.Driver连接串还要带时区和 SSL 参数否则 8.0 会甩你一个 SSL 警告甚至连接失败。2.2 建库建表五张核心表就够运动会管理系统的数据模型不复杂抓住「人、项目、报名、成绩、用户」五条线即可。下面这份 DDL 可以直接在 MySQL 里执行注意字符集统一用 utf8mb4否则运动员姓名里的生僻字会变问号。-- 创建数据库字符集必须显式指定 CREATE DATABASE sports_meet DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE sports_meet; -- 运动员表 CREATE TABLE athlete ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, gender TINYINT NOT NULL COMMENT 1男 2女, dept VARCHAR(50) COMMENT 院系/部门, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; -- 比赛项目表 CREATE TABLE event ( id INT PRIMARY KEY AUTO_INCREMENT, event_name VARCHAR(50) NOT NULL, event_type TINYINT COMMENT 1田赛 2径赛, max_persons INT DEFAULT 0 COMMENT 0表示不限, event_time DATETIME, place VARCHAR(50) ) ENGINEInnoDB; -- 报名表唯一索引防止同一人重复报同一项目 CREATE TABLE registration ( id INT PRIMARY KEY AUTO_INCREMENT, athlete_id INT NOT NULL, event_id INT NOT NULL, reg_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_athlete_event (athlete_id, event_id), FOREIGN KEY (athlete_id) REFERENCES athlete(id), FOREIGN KEY (event_id) REFERENCES event(id) ) ENGINEInnoDB; -- 成绩表成绩用字符串存兼容12.5秒1.8米这类带单位录入 CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, reg_id INT NOT NULL, result VARCHAR(30), rank_no INT DEFAULT 0, FOREIGN KEY (reg_id) REFERENCES registration(id) ) ENGINEInnoDB; -- 用户表role区分管理员和普通录入员 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) UNIQUE NOT NULL, password VARCHAR(64) NOT NULL, role TINYINT DEFAULT 2 COMMENT 1管理员 2普通用户 ) ENGINEInnoDB;registration表上的uk_athlete_event唯一索引是关键它把「同一人不能重复报同一项目」这条业务规则下沉到数据库层比在 Java 里先查再插更可靠能挡住并发下的重复提交。score表用reg_id关联而不是直接关联运动员是因为成绩属于「某人在某项目上的那次报名」这样一个人报多个项目时成绩不会串。2.3 JDBC 工具类一个能复用的连接封装Swing 是单线程事件模型数据库操作必须放到后台线程否则界面会假死。先写一个最简的连接工具类把 URL、账号密码集中管理后面所有 DAO 都用它。import java.sql.*; public class DBUtil { // 8.0 驱动写法5.7 把 cj 去掉、驱动类换成 com.mysql.jdbc.Driver private static final String URL jdbc:mysql://localhost:3306/sports_meet?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PWD 你的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new RuntimeException(驱动未加载检查jar是否加入classpath, e); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } // 统一关闭顺序不能反先ResultSet再Statement再Connection public static void close(Connection c, Statement s, ResultSet r) { try { if (r ! null) r.close(); } catch (SQLException ignored) {} try { if (s ! null) s.close(); } catch (SQLException ignored) {} try { if (c ! null) c.close(); } catch (SQLException ignored) {} } }连接串里useSSLfalse是为了绕开 8.0 默认开启 SSL 导致的握手告警本地开发够用serverTimezoneAsia/Shanghai不加的话插入的时间会差 8 小时这是血泪经验。close方法的关闭顺序不能颠倒先关结果集再关语句最后关连接反了会抛异常。工具类只做连接管理不掺业务逻辑这样后面换连接池比如 Druid时只改这一个文件。3. Swing 界面与业务逻辑把报名和计分跑起来3.1 主界面骨架与表格模型Swing 里展示列表数据标准做法是JTableDefaultTableModel不要用JList硬凑。主界面用JFrameBorderLayout中间放表格底部放按钮顶部放菜单栏。下面是一个运动员列表的最小可运行骨架。import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.util.List; public class MainFrame extends JFrame { private JTable table; private DefaultTableModel model; public MainFrame() { setTitle(运动会管理系统); setSize(900, 600); setDefaultCloseOperation(EXIT_ON_CLOSE); setLocationRelativeTo(null); // 居中别小看这行用户体验差很多 // 表头一旦确定后续只改数据行 String[] cols {ID, 姓名, 性别, 院系, 电话}; model new DefaultTableModel(cols, 0) { Override public boolean isCellEditable(int row, int col) { return false; // 表格只读编辑走弹窗避免误改 } }; table new JTable(model); table.setRowHeight(26); add(new JScrollPane(table), BorderLayout.CENTER); JPanel bottom new JPanel(); JButton addBtn new JButton(新增运动员); addBtn.addActionListener(e - openAddDialog()); bottom.add(addBtn); add(bottom, BorderLayout.SOUTH); loadData(); } // 从数据库加载实际项目要放到 SwingWorker 里 private void loadData() { model.setRowCount(0); ListAthlete list new AthleteDao().findAll(); for (Athlete a : list) { model.addRow(new Object[]{a.getId(), a.getName(), a.getGender() 1 ? 男 : 女, a.getDept(), a.getPhone()}); } } private void openAddDialog() { // 弹窗录入确认后刷新表格 new AthleteDialog(this).setVisible(true); loadData(); } }isCellEditable返回 false 是刻意为之表格直接编辑容易和数据库不同步统一走弹窗录入更可控。loadData里先setRowCount(0)清空再重填避免重复追加。真实项目里loadData要包在SwingWorker的doInBackground里done方法里再更新 model否则数据量大时界面会卡住不动。3.2 报名冲突检测与人数上限校验报名是这套系统业务最密的地方要同时满足三条规则同一人不能重复报同一项目、项目报名人数不能超上限、某些项目限制性别。这三条如果只在界面按钮里判断很容易被绕过正确做法是校验逻辑写在 Service 层DAO 只负责存取。public class RegistrationService { public String register(int athleteId, int eventId) { Connection conn null; try { conn DBUtil.getConn(); conn.setAutoCommit(false); // 开启事务校验和插入要么都成要么都不成 // 1. 查项目信息拿人数上限和性别限制 EventDao eventDao new EventDao(conn); Event event eventDao.findById(eventId); if (event null) return 项目不存在; // 2. 查是否已报名 RegistrationDao regDao new RegistrationDao(conn); if (regDao.exists(athleteId, eventId)) { return 该运动员已报名此项目; } // 3. 查当前报名人数是否已达上限 if (event.getMaxPersons() 0) { int count regDao.countByEvent(eventId); if (count event.getMaxPersons()) { return 报名人数已满; } } // 4. 插入报名记录 regDao.insert(athleteId, eventId); conn.commit(); return 报名成功; } catch (Exception e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ignored) {} e.printStackTrace(); return 报名失败 e.getMessage(); } finally { DBUtil.close(conn, null, null); } } }这里setAutoCommit(false)是核心把「查人数」和「插入」放进同一个事务避免两个管理员同时点报名时都查到 9 人、都插入、结果变成 11 人。返回字符串而不是抛异常是为了让界面层直接弹JOptionPane显示原因简单直接。注意exists查询和唯一索引是双保险索引兜底、代码给友好提示两者不冲突。3.3 成绩录入与排名并列处理成绩排名是运动会系统里最容易出玄学的地方。径赛成绩越小越好田赛成绩越大越好还有并列名次。常见做法是把成绩统一转成数值再排序但「12.5秒」和「1分02秒」这种混合格式必须先归一化。public class RankService { // 把成绩字符串转成可比较的秒数或米数返回null表示无法解析 public static Double parseResult(String result, int eventType) { if (result null || result.trim().isEmpty()) return null; result result.trim(); try { if (eventType 2) { // 径赛处理1分02秒和12.5秒 if (result.contains(分)) { String[] parts result.replace(秒, ).split(分); return Integer.parseInt(parts[0]) * 60 Double.parseDouble(parts[1]); } return Double.parseDouble(result.replace(秒, )); } else { // 田赛直接取米数 return Double.parseDouble(result.replace(米, )); } } catch (NumberFormatException e) { return null; // 解析失败交给上层提示 } } // 计算名次并列时占用相同名次后续名次跳号 public void calcRank(int eventId, int eventType) { ListScore list new ScoreDao().findByEvent(eventId); list.removeIf(s - parseResult(s.getResult(), eventType) null); // 径赛升序田赛降序 list.sort((a, b) - { double va parseResult(a.getResult(), eventType); double vb parseResult(b.getResult(), eventType); return eventType 2 ? Double.compare(va, vb) : Double.compare(vb, va); }); int rank 1; for (int i 0; i list.size(); i) { if (i 0) { double prev parseResult(list.get(i - 1).getResult(), eventType); double cur parseResult(list.get(i).getResult(), eventType); if (Math.abs(cur - prev) 1e-6) { rank i 1; // 成绩不同才更新名次相同则并列 } } new ScoreDao().updateRank(list.get(i).getId(), rank); } } }parseResult把不同格式统一成数值是排名的前提解析失败返回 null 而不是 0避免把无效成绩排到第一名。并列判断用Math.abs(cur - prev) 1e-6而不是直接!因为浮点数比较有精度问题这是很多人翻车的地方。名次跳号逻辑并列后下一个名次跳过符合正式比赛规则如果课程报告里要写算法说明这段就是现成素材。4. 避坑与排查那些让系统跑不起来的细节4.1 中文乱码从建库到界面全链路现象运动员姓名存进去变成问号或者界面显示方块。原因通常有三层数据库字符集不是 utf8mb4、连接串没带 characterEncoding、Swing 默认字体不支持中文。解决顺序是先SHOW VARIABLES LIKE character%确认库和表都是 utf8mb4再检查连接串有没有characterEncodingutf8最后确认运行环境有中文字体。三层缺一层都会乱码别只改一处就以为好了。4.2 界面假死与 EDT 线程违规现象点查询按钮后窗口卡住拖动无响应任务管理器显示 CPU 不高。原因是数据库查询写在了事件分发线程EDT里。Swing 所有界面更新必须在 EDT但耗时操作必须挪出去。解决是用SwingWorkerdoInBackground里查数据库done里更新表格。判断是否违规有个简单办法在按钮监听里打印SwingUtilities.isEventDispatchThread()返回 true 说明你正在 EDT 里干重活。4.3 外键约束导致删数据失败现象删除运动员时报Cannot delete or update a parent row。原因是registration表有外键指向athlete。解决有两种先删报名记录再删运动员或者建表时加ON DELETE CASCADE。课程设计里推荐前者手动控制删除顺序逻辑更清晰也方便在报告里讲数据完整性。用级联删除虽然省事但误删时没有后悔药。4.4 事务没提交导致数据「消失」现象代码里 insert 执行没报错但重新查询查不到。原因是开了setAutoCommit(false)却忘了commit()连接关闭时自动回滚。这个坑在报名和成绩录入里最常见。排查方法是看代码里setAutoCommit(false)之后有没有配对的commit以及异常分支里有没有rollback。养成习惯只要手动开事务就用 try-catch-finally 把提交和回滚写全。4.5 驱动版本与 SSL 连接报错现象8.0 数据库报Establishing SSL connection without servers identity verification is not recommended或者直接连接超时。原因是 8.0 默认要求 SSL 且时区参数缺失。解决是在连接串加useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue。allowPublicKeyRetrievaltrue在首次连接时能避免公钥检索失败本地开发加上无妨生产环境要按实际安全策略调整。5. 课程报告怎么写才不像流水账课程报告最容易写成「我用了什么技术」的清单评审老师看三页就腻。真正加分的写法是围绕「一个具体问题怎么被解决」展开。比如报名人数上限不要只写「用了事务」而要写清楚并发场景下先查后插会产生超卖所以把校验和插入放进同一事务配合唯一索引兜底最后给出测试方法——开两个客户端同时报名最后一个名额观察是否只有一个成功。这种「问题—方案—验证」的结构比堆砌名词有说服力。再比如排名并列报告里可以放一张对比表说明直接按字符串排序和归一化后排序的差异附上「1分02秒」和「12.5秒」的实际排序结果。数据库设计部分把 ER 图用文字描述清楚实体和联系重点讲为什么成绩表关联报名表而不是运动员表。测试章节列三到五个边界用例报名人数刚好等于上限、成绩为空、删除有报名的运动员、重复报名同一项目、并列名次。每个用例写输入、预期、实际这种报告拿高分不难。我自己的习惯是先把系统跑通再回头补报告因为很多设计理由是在调试过程中才想明白的。写报告时把调试日志和报错截图留一份比事后编造更有细节。这套 Java Swing MySQL 的运动会管理系统技术栈不新但把事务、并发校验、界面线程、字符集这些基础问题串了一遍做完一遍对桌面应用和数据库的理解会扎实很多。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询