【问题标题】:How to insert a Clob into a Oracle table with Slick 3 and Oracle 12?如何使用 Slick 3 和 Oracle 12 将 Clob 插入到 Oracle 表中?
【发布时间】:2017-08-25 20:39:00
【问题描述】:
  • 我们有一个带有 CLOB 列的表(用于保存 JSON 数据)
  • 据我们了解(来自文档)光滑的支持 LOB 类型 (http://slick.lightbend.com/doc/3.1.1/schemas.html)
  • 我们能够成功查询该表。包括 CLOB 列。
  • 我们无法使用 Clob 插入寄存器。我们正在将 String 转换为 java.sql.Clob :

    private java.sql.Clob stringToClob(String source)
    {
        try
        {
            return new javax.sql.rowset.serial.SerialClob(source.toCharArray());
        }
        catch (Exception e)
        {
            log.error("Could not convert string to a CLOB",e);
            return null;
        }
    }
    

但最终,slick 的例外情况如下:

java.lang.ClassCastException: javax.sql.rowset.serial.SerialClob cannot be cast to oracle.sql.CLOB

这可能吗?

【问题讨论】:

    标签: oracle scala slick slick-3.0


    【解决方案1】:

    我们终于找到了一个解决方法,如下:

    根据 slick 中的column 定义

    def column[C](n: String, options: ColumnOption[C]*)(implicit tt: TypedType[C]): Rep[C]
    

    您可以指定如何在驱动程序和您的代码之间转换列。如果您想使用开箱即用的翻译,但对于 Oracle,CLOB 类型的翻译似乎无法正常工作。

    我们所做的是将列定义为String,但让 Slick 使用我们的自定义代码处理翻译。列定义如下:

    def myClobColumn = column[String]( "CLOBCOLUMN" )( new StringJdbcType )
    

    asd

    作为StringJdbcType我们的自定义代码来解决我们要插入的String(最多65535字节)和OracleCLOB之间的转换。

    StringJdbcType的代码如下:

    class StringJdbcType extends driver.DriverJdbcType[String] {
      def sqlType = java.sql.Types.VARCHAR
      // Here's the solution
      def setValue( v: String, p: PreparedStatement, idx: Int ) = {
        val conn = p.getConnection
        val clob = conn.createClob()
        clob.setString( 1, v )
        p.setClob( idx, clob )
      }
      def getValue( r: ResultSet, idx: Int ) = scala.io.Source.fromInputStream( r.getAsciiStream( "DSPOLIZARIESGO" ) )( Codec.ISO8859 ).getLines().mkString
      def updateValue( v: String, r: ResultSet, idx: Int ) = r.updateString( idx, v )
      override def hasLiteralForm = false
    }
    

    setValue 函数是我们的救星,因为我们可以使用已经实例化的 PreparedStatement 和来自我们域的字符串来构建 Oracle CLOB。在我们的实现中,我们只需要为 Oracle CLOB 做管道和脏活。

    总而言之,Slick 在driver.DriverJdbcType[A] 中提供的扩展点是我们实际用于使事情工作的东西。

    【讨论】:

    • 您好 juanpavergara,相同的实现,但是当列 clob 值非常大时,我们会遇到 OOMI 问题。这是表类中的列定义: def clobColumn = column[String]( "CLOBCOLUMN", O.Length( 50000 ) )( new StringJdbcType ) 事实上,我们想知道是否可以设置 BufferedSource 的长度,其中我们正在建造它。
    【解决方案2】:

    这些是与解决方案相关的一些改进:关闭资源和流检查

      class BigStringJdbcType
        extends profile.DriverJdbcType[String] {
    
        def sqlType: Int = java.sql.Types.VARCHAR
    
        def setValue(v: String, p: PreparedStatement, idx: Int): Unit = {
          val connection = p.getConnection
          val clob = connection.createClob()
          try {
            clob.setString(1, v)
            p.setClob(idx, clob)
          } finally {
            clob.free()
          }
        }
    
        def getValue(r: ResultSet, idx: Int): String = {
          val asciiStream = r.getAsciiStream(idx)
          try {
            val (bufferEmpty, encoding) = getInputStreamStatus(asciiStream)
    
            if (bufferEmpty) {
              convertInputStreamToString(asciiStream, encoding)
            } else ""
    
          } finally {
            asciiStream.close()
          }
        }
    
        def updateValue(v: String, r: ResultSet, idx: Int): Unit =
          r.updateString(idx, v)
    
        override def hasLiteralForm: Boolean = false
      } 
    

    补充解决方案的一些实用程序

      def getInputStreamStatus(stream: InputStream): (Boolean, String) = {
        val reader = new InputStreamReader(stream)
        try {
          val bufferEmpty = reader.ready()
          val encoding = reader.getEncoding
          bufferEmpty -> encoding
    
        } finally {
          reader.close()
        }
      }
    
      def convertInputStreamToString(
        stream: InputStream,
        encoding: String
      ): String = {
        scala.io.Source.fromInputStream(stream)(encoding).getLines().mkString
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 2021-02-12
      相关资源
      最近更新 更多