SqlRowSet 抛出具有 dateTimeOffset 的列的无效 SQL 类型(与 java Instant 关联的类型)

问题描述 投票:0回答:1

我已将我的应用程序升级到 Springboot 3(Hibernate 6),现在 Instant 作为 datetimeoffset 存储在 sql server 中。我有几个查询使用 SqlRowSet 返回上次修改日期和创建日期。问题在于这种方法在内部调用方法(checkColType),该方法使用java.sql.Types.class,该类没有任何datetimeoffset(-155 sqlType)字段,因为此checkColType会引发异常。 有什么方法可以解决这个问题,或者我应该返回到 java Instant 的旧数据类型(日期时间)。

public class RowSetMetaDataImpl implements RowSetMetaData,  Serializable {
private void checkColType(int SQLType) throws SQLException {
    try {
        Class<?> c = java.sql.Types.class;
        Field[] publicFields = c.getFields();
        int fieldValue = 0;
        for (int i = 0; i < publicFields.length; i++) {
            fieldValue = publicFields[i].getInt(c);
            if (fieldValue == SQLType) {
                return;
             }
        }
    } catch (Exception e) {
        throw new SQLException(e.getMessage());
    }
    throw new SQLException("Invalid SQL type for column");
}
}

即使在 com.microsoft.sqlserver.jdbc.SSType DATETIMEOFFSET 中,也会与 java.sql.Types 中不存在的 microsoft.sql.Types.DATETIMEOFFSET 进行映射,而 RowSetMetaDataImpl 仅使用 java.sql.Types。

代码意图:我们的团队编写了各种即席本机 SQL 查询,其结果集我们用 Excel 编写。使用 SqlRowSet 我们获取列元数据并写入标题,即使数据不存在也是如此。如果存在数据,则数据也会写入 Excel 中。我们的团队不可能在这么多客户端上重写查询。我还附上了我们用来写入数据的方法。

public Path exportDefaultView(List<QueryExcelSheetConfig> queryExcelSheetConfigs) throws Exception {
    Workbook wb = new Workbook();
    Path temp = Files.createTempFile("temp", ".xlsx");
    try (InputStream is = Files.newInputStream(temp)) {
        wb.getWorksheets().removeAt(0);
        for (QueryExcelSheetConfig queryConfig : queryExcelSheetConfigs) {
            String sheetName = queryConfig.getSheetName().replaceAll("[^a-zA-Z0-9._]+", "_");
            Worksheet ws = wb.getWorksheets().add(sheetName);
            SqlRowSet sqlRowSet = namedParameterJdbcTemplate.queryForRowSet("dynamic query from db",
                    queryConfig.getArguments());
            SqlRowSetMetaData metaData = sqlRowSet.getMetaData();
            Cells cells = ws.getCells();
            IntStream.range(0, metaData.getColumnCount()).forEach(colNum -> {
                Cell cell = cells.get(0, colNum);
                cell.setValue(metaData.getColumnName(colNum + 1));
            });
            while (sqlRowSet.next()) {
                IntStream.range(0, metaData.getColumnCount()).forEach(colNum -> {
                    Cell cell = cells.get(sqlRowSet.getRow(), colNum);
                    setCellValue(cell, colNum + 1, sqlRowSet, metaData);
                });
            }
            wb.getWorksheets().get(sheetName).autoFitColumns();
        }
        wb.save(temp.toString());
    } finally {
        wb.dispose();
    }
    return temp;
}

解决方案:

public ResultRecord executeSelectSqlQueryForResultRecord(String query, Map<String, Object> data) {
    NamedParameterJdbcTemplate loadBalancedDB = getLoadBalancedDB();
    loadBalancedDB.getJdbcTemplate().setQueryTimeout(SELECT_QUERY_TIMEOUT);
    loadBalancedDB.getJdbcTemplate().setFetchSize(1000);
    
    boolean enableAllResultSet = data != null && data.containsKey("enableAllResultSet");
    final ResultRecord result1 = loadBalancedDB.query(query, data, rs -> {
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        Map<String, Object> values = null;
        List<String> columns = new ArrayList<>(columnCount);
        for (int i = 1; i <= columnCount; i++) {
            columns.add(JdbcUtils.lookupColumnName(rsmd, i));
        }
        
        List<Map<String, Object>> result = new LinkedList<>();
        int count = 0;
        while (rs.next()) {
            values = new LinkedCaseInsensitiveMap<>(columnCount);
            count++;
            for (int i = 1; i <= columnCount; i++) {
                values.putIfAbsent(columns.get(i-1), JdbcUtils.getResultSetValue(rs, i));
            }
            result.add(values);
            if (count > 50000 && !enableAllResultSet)
                break;
        }
        rs.close();
        return new ResultRecord(result, columns);
    });

    if (result1.result().size() > 50000 && !enableAllResultSet) {
        throw new DataException("Result set size cannot be greater than 50000. " + "Please pass \"enableAllResultSet\" as one of the argument to disable this check.");
    }

    return result1;
}
java sql-server spring-boot hibernate jdbc
1个回答
0
投票

我用这个方法解决了我的问题。

public ResultRecord executeSelectSqlQueryForResultRecord(String query, Map<String, Object> data) {

NamedParameterJdbcTemplate loadBalancedDB = getLoadBalancedDB();
loadBalancedDB.getJdbcTemplate().setQueryTimeout(SELECT_QUERY_TIMEOUT);
loadBalancedDB.getJdbcTemplate().setFetchSize(1000);

boolean enableAllResultSet = data != null && data.containsKey("enableAllResultSet");
final ResultRecord result1 = loadBalancedDB.query(query, data, rs -> {
    ResultSetMetaData rsmd = rs.getMetaData();
    int columnCount = rsmd.getColumnCount();
    Map<String, Object> values = null;
    List<String> columns = new ArrayList<>(columnCount);
    for (int i = 1; i <= columnCount; i++) {
        columns.add(JdbcUtils.lookupColumnName(rsmd, i));
    }
    
    List<Map<String, Object>> result = new LinkedList<>();
    int count = 0;
    while (rs.next()) {
        values = new LinkedCaseInsensitiveMap<>(columnCount);
        count++;
        for (int i = 1; i <= columnCount; i++) {
            values.putIfAbsent(columns.get(i-1), JdbcUtils.getResultSetValue(rs, i));
        }
        result.add(values);
        if (count > 50000 && !enableAllResultSet)
            break;
    }
    rs.close();
    return new ResultRecord(result, columns);
});

if (result1.result().size() > 50000 && !enableAllResultSet) {
    throw new DataException("Result set size cannot be greater than 50000. " + "Please pass \"enableAllResultSet\" as one of the argument to disable this check.");
}

return result1;
}
© www.soinside.com 2019 - 2024. All rights reserved.