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

Java中如何将Oracle数据库查询结果与Excel文件数据做对比校验

Oracle数据与Excel预期数据对比校验实现方案

现有实现优化点

你当前的实现已经完成了数据转换的核心流程,但是还存在几个潜在问题需要修复:

  • User类未重写equals方法:如果你的User类没有重写equals和hashCode方法,默认的列表对比会按对象内存地址判断,永远不相等
  • 资源未安全释放:当前的文件流读取未做自动关闭处理,遇到异常时容易出现资源泄漏
  • 单元格类型兼容不足:直接调用getStringCellValue()读取单元格内容,当Excel单元格是数字、空值、日期格式时会直接抛出类型转换异常
  • 列表对比强依赖顺序:直接用assertEquals对比两个列表,会严格校验元素顺序,如果数据库查询结果排序和Excel行顺序不一致,会出现误报
  • 错误提示不直观:原生列表相等校验失败时只会输出列表不相等,无法定位到具体是哪一行、哪个字段存在差异

优化后实现代码

1. 改进Excel转对象方法

public static List<User> convertExcelFileToObject(String filePath) {
    ArrayList<User> usersList = new ArrayList<>();
    // 用try-with-resources自动关闭流资源
    try (FileInputStream file = new FileInputStream(filePath);
         XSSFWorkbook workbook = new XSSFWorkbook(file)) {
        XSSFSheet sheet = workbook.getSheetAt(0);
        DataFormatter dataFormatter = new DataFormatter(); // 兼容所有单元格类型转字符串
        for(int i = sheet.getFirstRowNum() + 1; i <= sheet.getLastRowNum(); i++){
            User user = new User();
            Row row = sheet.getRow(i);
            if(row == null) continue; // 跳过空行
            for(int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++){
                Cell cell = row.getCell(j);
                // 统一转字符串,兼容数字、空值等格式,自动去除首尾空格
                String cellValue = dataFormatter.formatCellValue(cell).trim();
                if(j == 0){
                    user.setUserId(cellValue);
                } else if(j == 1){
                    user.setUserName(cellValue);
                } else if(j == 2){
                    user.setSurnameName(cellValue);
                }
            }
            usersList.add(user);
        }
    } catch (Exception e) {
        throw new RuntimeException("Excel文件解析失败", e);
    }
    return usersList;
}

2. 改进DB结果转对象方法

public static List<User> convertDbResultsToObject(String sqlQuery) throws SQLException {
    // ResultSet也放在try-with-resources里自动关闭
    try (ResultSet resultSet = DatabaseManager.getData(sqlQuery)) {
        List<User> users = new ArrayList<>();
        while(resultSet.next()) {
            User user = new User();
            // 读取数据库字段时也做trim和空值处理,避免空格、NULL导致的不一致
            user.setUserId(resultSet.getString("USER_ID") == null ? "" : resultSet.getString("USER_ID").trim());
            user.setUserName(resultSet.getString("USER_NAME") == null ? "" : resultSet.getString("USER_NAME").trim());
            user.setSurnameName(resultSet.getString("SURNAME_NAME") == null ? "" : resultSet.getString("SURNAME_NAME").trim());
            users.add(user);
        }
        return users;
    }
}

3. 精准对比方法实现

不用直接对比列表,先按唯一主键分组,逐字段对比,输出精准错误信息

public void assertUserListEquals(List<User> expectedExcelList, List<User> actualDbList) {
    // 先按userId转成Map,不用关心两边数据的排序问题
    Map<String, User> expectedMap = expectedExcelList.stream().collect(Collectors.toMap(User::getUserId, Function.identity()));
    Map<String, User> actualMap = actualDbList.stream().collect(Collectors.toMap(User::getUserId, Function.identity()));
    
    // 先校验两边主键集合完全一致
    assertEquals("Excel和数据库的用户ID集合不一致", expectedMap.keySet(), actualMap.keySet());
    
    // 逐行逐字段对比,错误信息直接提示异常的用户ID和字段名
    for (String userId : expectedMap.keySet()) {
        User expected = expectedMap.get(userId);
        User actual = actualMap.get(userId);
        assertEquals("用户ID:" + userId + "的USER_NAME不一致", expected.getUserName(), actual.getUserName());
        assertEquals("用户ID:" + userId + "的SURNAME_NAME不一致", expected.getSurnameName(), actual.getSurnameName());
    }
}

其他可选简化方案

如果不需要绑定特定对象,想要更通用的对比逻辑,可以把Excel和数据库结果都转成List<Map<String, Object>>格式,不用为每个表单独写对象转换代码,适配多表校验的场景。
如果愿意调整文件格式,换成CSV格式的话可以不用引入POI依赖,直接用BufferedReader读取,解析逻辑更轻量,适合简单场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:24:01