You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何员工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();
    }
}
额外优化建议
  1. 不要在函数内反复创建数据库连接,可以提前创建好连接并传入函数,避免频繁建立/断开连接的开销。
  2. 依赖数据库主键唯一性约束,即使前端校验出现疏漏,数据库层面也能阻止重复ID插入,避免数据不一致。
  3. 递归调用可以替换为循环,避免栈溢出风险(虽然实际场景中用户输入次数有限,但循环更稳妥)。

内容的提问来源于stack exchange,提问作者user20504992

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:45:57