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

Slick 3.5.1中Oracle LocalDateTime仅支持3位纳秒解析导致ORA-01830错误的全局解决方案问询

Slick 3.5.1中Oracle LocalDateTime仅支持3位纳秒解析导致ORA-01830错误的全局解决方案问询

我之前也碰到过类似的问题,Slick默认的OracleProfile对LocalDateTime的处理确实有点坑——它硬把纳秒精度编码成了3位,和Java LocalDateTime默认的9位纳秒完全不匹配,直接就触发ORA-01830错误了。不过不用慌,我们可以通过全局重写OracleProfile的类型映射来彻底解决这个问题,不用在每个查询里手动改时间格式。下面给你两个靠谱的方案:

方案一:自定义OracleProfile,支持9位纳秒全精度

这个方案适合需要保留完整纳秒精度的场景,核心是重写LocalDateTime的类型映射,让Slick生成的SQL使用FF9格式(支持9位纳秒),而不是默认的FF3。

首先创建一个自定义的OracleProfile:

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import slick.jdbc.OracleProfile
import slick.jdbc.PositionedParameters
import slick.jdbc.PositionedResult
import slick.ast.FieldSymbol

object CustomOracleProfile extends OracleProfile {
  override val api: API = new API {}

  trait API extends super.API {
    // 重写LocalDateTime的全局类型映射
    implicit override lazy val localDateTimeTypeMapper: BaseTypeMapper[LocalDateTime] =
      new BaseTypeMapper[LocalDateTime] {
        // 用于格式化Java LocalDateTime为9位纳秒的字符串
        private val javaDateTimeFormatter = DateTimeFormatter.ofPattern("dd-MMM-yy HH:mm:ss.SSSSSSSSS")
        // Oracle TO_TIMESTAMP对应的格式串(支持9位纳秒)
        private val oracleTimestampPattern = "DD-Mon-RR HH24:MI:SS.FF9"

        override def sqlType: Int = java.sql.Types.TIMESTAMP
        override def sqlTypeName(sym: Option[FieldSymbol]): String = "TIMESTAMP(9)"

        // 把LocalDateTime转成Oracle能识别的SQL字面量
        override def valueToSQLLiteral(value: LocalDateTime): String = {
          val formattedTime = javaDateTimeFormatter.format(value)
          s"TO_TIMESTAMP('$formattedTime', '$oracleTimestampPattern')"
        }

        // 处理参数绑定,确保写入数据库时保留全精度
        override def setParameter(v: LocalDateTime, pp: PositionedParameters): Unit = {
          pp.setTimestamp(java.sql.Timestamp.valueOf(v))
        }

        // 处理结果集读取,确保从数据库读回时保留全精度
        override def getResult(r: PositionedResult): LocalDateTime = {
          r.nextTimestamp().toLocalDateTime
        }
      }
  }
}

然后,把项目中所有引用默认OracleProfile的地方,全部替换成这个自定义的Profile:

// 原来的导入要注释掉
// import slick.jdbc.OracleProfile.api._
// 换成自定义的Profile
import CustomOracleProfile.api._

这样之后,Slick生成的SQL就会自动用FF9格式,和Java LocalDateTime的9位纳秒完全匹配,不会再出现格式不匹配的错误。

方案二:全局截断纳秒到3位(适合不需要全精度的场景)

如果你的业务不需要9位纳秒精度,也可以选择全局把LocalDateTime的纳秒截断到3位,和Slick默认的格式兼容。同样通过重写Profile实现:

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import slick.jdbc.OracleProfile
import slick.jdbc.PositionedParameters
import slick.jdbc.PositionedResult
import slick.ast.FieldSymbol

object TruncatedOracleProfile extends OracleProfile {
  override val api: API = new API {}

  trait API extends super.API {
    implicit override lazy val localDateTimeTypeMapper: BaseTypeMapper[LocalDateTime] =
      new BaseTypeMapper[LocalDateTime] {
        private val javaDateTimeFormatter = DateTimeFormatter.ofPattern("dd-MMM-yy HH:mm:ss.SSS")
        private val oracleTimestampPattern = "DD-Mon-RR HH24:MI:SS.FF3"

        override def sqlType: Int = java.sql.Types.TIMESTAMP
        override def sqlTypeName(sym: Option[FieldSymbol]): String = "TIMESTAMP(3)"

        override def valueToSQLLiteral(value: LocalDateTime): String = {
          // 把纳秒截断到3位(除以1000000后取整再乘回去)
          val truncatedTime = value.withNano((value.getNano / 1000000) * 1000000)
          val formattedTime = javaDateTimeFormatter.format(truncatedTime)
          s"TO_TIMESTAMP('$formattedTime', '$oracleTimestampPattern')"
        }

        override def setParameter(v: LocalDateTime, pp: PositionedParameters): Unit = {
          val truncatedTime = v.withNano((v.getNano / 1000000) * 1000000)
          pp.setTimestamp(java.sql.Timestamp.valueOf(truncatedTime))
        }

        override def getResult(r: PositionedResult): LocalDateTime = {
          r.nextTimestamp().toLocalDateTime
        }
      }
  }
}

同样,替换项目中的Profile导入即可,这种方案的好处是完全兼容Slick原来的逻辑,只是截断了精度,不会引入新的格式问题。

小提示

不管用哪个方案,一定要确保项目中所有使用OracleProfile的地方都替换成自定义的版本,包括DAO层、查询定义的地方,这样才能真正实现全局生效。

备注:内容来源于stack exchange,提问作者M. Barabas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 15:43:00