JDK8+Spring Boot1.5.3与JDK21+Spring Boot2.7.16存储过程日期返回类型差异
存储过程返回日期类型跨环境差异的原因分析与解决办法
执行存储过程后,ScheduledStartDate字段的返回值在不同环境存在明显差异:
- JDK 8 + Spring Boot 1.5.3-RELEASE:返回时间戳格式(如
1704479400000) - JDK 21 + Spring Boot 2.7.16:返回日期时间字符串格式(如
2024-01-06 17:00:00.0)
相关代码
Java执行代码:
Map<String, Object> result = simpleJdbcCall.execute(sqlParameter);
存储过程代码:
BEGIN SELECT * FROM WorkOrder WHERE (RowNo BETWEEN @PageSize * (@PageNumber - 1) + 1 AND @PageNumber * @PageSize) OR (RowNo = 0 AND FromDate >= @FromDate AND FromDate < @Todate) ORDER BY DeliveryDate, status, WorkOrderID, FromDate END
已尝试将MS SQL Server驱动从12.4降级至6.4,问题未解决。
原因分析
- Spring JDBC版本逻辑差异:Spring Boot 2.x依赖的Spring 5.x对比1.x的Spring 4.x,对JDBC类型映射逻辑做了调整。Spring 5.x强化了对Java 8+日期API(如
LocalDateTime)的原生支持,不再默认将数据库日期类型转为时间戳,而是根据驱动返回的类型直接映射,导致表现差异。 - JDK与驱动的适配逻辑变化:SQL Server驱动的类型转换行为会随JDK版本变化。即使降级驱动到6.4,该版本在JDK 21环境下的类型解析逻辑和JDK 8环境下不一致——比如对
java.sql.Timestamp和字符串的优先级处理不同,最终导致返回格式变化。 - 连接属性默认值差异:Spring Boot 2.x默认的数据库连接属性和1.x存在差异,例如SQL Server驱动的
sendTimeAsDatetime参数,该参数不仅影响发送到数据库的日期格式,也会影响数据库返回日期时的解析方式,默认值的变化可能引发返回类型不同。
解决办法
1. 显式指定字段类型映射
在SimpleJdbcCall中通过declareParameters明确指定ScheduledStartDate的JDBC类型,强制Spring JDBC将其映射为Timestamp,再转换为时间戳:
simpleJdbcCall.declareParameters( new SqlOutParameter("ScheduledStartDate", Types.TIMESTAMP) );
2. 统一代码层的日期转换逻辑
在获取返回值后,针对不同类型做统一转换,确保输出一致:
Object scheduledStartObj = result.get("ScheduledStartDate"); long scheduledStartTimestamp; if (scheduledStartObj instanceof String) { // 解析日期字符串为时间戳 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"); LocalDateTime dateTime = LocalDateTime.parse((String) scheduledStartObj, formatter); scheduledStartTimestamp = dateTime.atZone(ZoneId.systemDefault()) .toInstant() .toEpochMilli(); } else if (scheduledStartObj instanceof Long) { scheduledStartTimestamp = (Long) scheduledStartObj; } else if (scheduledStartObj instanceof Timestamp) { scheduledStartTimestamp = ((Timestamp) scheduledStartObj).getTime(); } else { // 处理其他异常情况 scheduledStartTimestamp = 0; }
3. 统一数据库连接属性
在配置文件中显式设置SQL Server驱动的相关参数,对齐新旧环境的行为:
# application.properties spring.datasource.hikari.data-source-properties.sendTimeAsDatetime=true spring.datasource.hikari.data-source-properties.useFmtOnly=false
4. 升级适配JDK 21的驱动版本
驱动6.4对JDK 21的支持并不完善,建议升级到官方支持JDK 21的最新SQL Server驱动版本(如12.6及以上),新版本通常会修复跨JDK版本的类型映射问题。
内容的提问来源于stack exchange,提问作者Sreejesh
相关产品推荐
相关产品推荐

