为何员工ID唯一性校验仅对小于10的数字生效?
问题描述
录入数据时使用checkUnique()函数校验员工ID是否已存在于数据库中,该函数在注册场景可正常工作,但仅能识别小于10的已存在ID(例如ID=2会提示重复,ID=12却被跳过)。相关代码及表结构如下:
唯一性校验函数代码
private int checkUnique() { try { Scanner scan = new Scanner(System.in); id = scan.nextInt(); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:...", "...", "..."); Statement st = connection.createStatement(); ResultSet res = st.executeQuery("select id_emp from employees"); while (res.next()) { if (res.getInt("id_emp")==getId()) { res.close(); st.close(); connection.close(); System.out.println("There is employee with this id"); System.out.println("Enter id"); checkUnique(); } else { res.close(); st.close(); connection.close(); return id; } } } catch (Exception e) { e.printStackTrace(); } return 0; }
函数调用代码
Statement st = connection.createStatement(); String sql = "INSERT INTO employees (id_emp, first_name, last_name, cnt_kids, cnt_dkids,is_single,added_by) " + "VALUES (?, ?, ?, ?, ?,?,?)"; PreparedStatement ps = connection.prepareStatement(sql); System.out.println("Enter id"); id = checkUnique();
MySQL表结构
CREATE TABLE `employees` ( `id_emp` int NOT NULL, `first_name` varchar(30) DEFAULT NULL, `last_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, `cnt_kids` int DEFAULT NULL, `cnt_dkids` int DEFAULT NULL, `is_single` bit(1) DEFAULT NULL, `added_by` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, PRIMARY KEY (`id_emp`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
问题分析
- 结果集遍历逻辑完全错误:函数只检查结果集中的第一条记录。如果第一条ID和输入ID不匹配,直接关闭所有资源并返回当前输入的ID,完全没有遍历后续的记录。这就是ID=12这类排在后面的重复ID会被跳过的核心原因——程序根本没查到那条记录。
- 递归调用未处理返回值:当发现ID重复时,递归调用
checkUnique()让用户重新输入,但没有把递归得到的新ID返回。这会导致最终返回的还是最初输入的重复ID,而不是用户重新输入的有效ID。 - 资源管理混乱:每次循环都强制关闭数据库连接、Statement和ResultSet,不仅逻辑错误,还会导致资源泄漏。递归调用时会创建多个数据库连接,进一步加剧资源浪费。
- 查询效率极低:每次校验都全表查询所有员工ID,完全没必要。直接通过带条件的SQL查询指定ID是否存在即可,而且利用主键索引能大幅提升效率。
修复后的代码示例
private int checkUnique() { Scanner scan = new Scanner(System.in); try { System.out.print("Enter id: "); int inputId = scan.nextInt(); // 直接查询指定ID是否存在,利用主键索引高效查询 String sql = "SELECT id_emp FROM employees WHERE id_emp = ?"; try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:...", "...", "..."); PreparedStatement ps = connection.prepareStatement(sql)) { ps.setInt(1, inputId); try (ResultSet res = ps.executeQuery()) { if (res.next()) { // ID已存在,提示后递归获取新ID,并返回递归结果 System.out.println("There is employee with this id"); return checkUnique(); } else { // ID不存在,直接返回 return inputId; } } } } catch (Exception e) { e.printStackTrace(); System.out.println("Error checking ID uniqueness, please try again"); // 出错后重新获取ID return checkUnique(); } }
额外优化建议
- 不要在函数内反复创建数据库连接,可以提前创建好连接并传入函数,避免频繁建立/断开连接的开销。
- 依赖数据库主键唯一性约束,即使前端校验出现疏漏,数据库层面也能阻止重复ID插入,避免数据不一致。
- 递归调用可以替换为循环,避免栈溢出风险(虽然实际场景中用户输入次数有限,但循环更稳妥)。
内容的提问来源于stack exchange,提问作者user20504992
相关产品推荐
相关产品推荐

