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
相关产品推荐
相关产品推荐

