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

升级Oracle JDBC Driver从11到17触发ORA-18716时区错误求助

解决ojdbc17升级后ORA-18716时区敏感类型错误

问题场景

将Spring Boot 3.5.3应用的JDBC驱动版本从:

runtimeOnly "com.oracle.database.jdbc:ojdbc11:version: '21.8.0.0'"
liquibaseRuntime "com.oracle.database.jdbc:ojdbc11:version: '21.8.0.0'"

升级为:

runtimeOnly "com.oracle.database.jdbc:ojdbc17:version: '23.8.0.25.04'"
liquibaseRuntime "com.oracle.database.jdbc:ojdbc17:version: '23.8.0.25.04'"

后触发错误:

ORA-18716: {0} not in any time zone.DATE

错误提示说明使用OffsetDateTime、OffsetTime或ZonedDateTime等时区敏感类型时,输入数据必须包含时区信息。已实现DateMapper接口处理Instant到OffsetDateTime的转换:

public interface DateMapper {
    default OffsetDateTime fromInstant(Instant instant) {
        return Objects.isNull(instant)
            ? null
            : OffsetDateTime.ofInstant(instant, java.time.ZoneOffset.UTC);
    }
}

但问题仍未解决,需技术帮助。


实用解决方向

1. 调整JDBC连接属性

ojdbc17对时区类型的校验比ojdbc11更严格,在数据库连接URL中添加以下参数:

jdbc:oracle:thin:@//your-db-host:port/service_name?oracle.jdbc.timezoneAsRegion=false&oracle.jdbc.timestampTzInGmt=true
  • oracle.jdbc.timezoneAsRegion=false:禁用时区区域名称解析,强制使用偏移量处理
  • oracle.jdbc.timestampTzInGmt=true:将TIMESTAMP WITH TIME ZONE类型统一转换为GMT时区的OffsetDateTime,避免本地时区干扰

2. 对齐实体类与数据库列类型

确认实体类中使用OffsetDateTime等时区敏感类型的字段,对应的数据库列必须是TIMESTAMP WITH TIME ZONE,而非普通DATE或TIMESTAMP。如果无法修改数据库列类型,需调整实体类字段类型:

// 示例:将OffsetDateTime转为LocalDateTime(需确认业务允许丢失时区信息)
default LocalDateTime offsetToLocal(OffsetDateTime offsetDateTime) {
    return offsetDateTime != null ? offsetDateTime.toLocalDateTime() : null;
}

3. 修正Liquibase脚本的日期处理

升级liquibaseRuntime后,变更集里的日期操作也会触发严格校验:

  • 插入/更新TIMESTAMP WITH TIME ZONE列时,使用带时区的日期格式,比如'2024-01-01T12:00:00+00:00'
  • 生成日期时使用SYSTIMESTAMP而非SYSDATE,确保返回带时区的类型

4. 配置Hibernate/JPA的时区映射(若使用)

如果项目依赖Hibernate,添加以下JPA配置:

spring.jpa.properties.hibernate.jdbc.time_zone=UTC
spring.jpa.properties.hibernate.type.preferred_instant_jdbc_type=TIMESTAMP_WITH_TIMEZONE

让Hibernate自动将Instant/OffsetDateTime绑定到数据库的TIMESTAMP WITH TIME ZONE列,避免类型不匹配。

5. 覆盖所有日期转换场景

现有DateMapper仅处理了Instant到OffsetDateTime的转换,需排查其他未覆盖的场景:

  • 数据库DATE列直接映射到OffsetDateTime
  • 前端传入无时区标识的字符串日期转为OffsetDateTime
    补充对应转换逻辑:
// 示例:将无时区字符串转为UTC时区的OffsetDateTime
default OffsetDateTime stringToOffset(String dateStr) {
    if (dateStr == null) return null;
    LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
    return localDateTime.atOffset(ZoneOffset.UTC);
}

内容的提问来源于stack exchange,提问作者Murat K.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:28:13