我已将我的应用程序升级到 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;
}
我用这个方法解决了我的问题。
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;
}