【问题标题】:Oracle jdbc "createArray" throws "Unsupported feature" exception while trying to pass array to prepared statement [duplicate]Oracle jdbc“createArray”在尝试将数组传递给准备好的语句时抛出“不支持的功能”异常[重复]
【发布时间】:2017-06-19 22:31:57
【问题描述】:

我正在尝试通过执行 createArrayOf

将数组传递给我准备好的语句
val prep: PreparedStatement = con.prepareStatement("select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in (?)")

val array :Array[Object]=Array("1165006001","1165006002")

val sqlArray = con.createArrayOf("VARCHAR",array) //getting the exception here 

prep.setArray(1,sqlArray)

val rs = prep.executeQuery()

while (rs.next()) {

    println(rs.getObject(1))

}

但是 createArrayOf 方法抛出一个错误说

Exception  thread "main" java.sql.SQLFeatureNotSupportedException:Unsupported feature   
at Oracle.jdbc.driver.PhysicalConnection.createArrayOf(PhysicalConnection.java:8707)
at com.testpackage.Main$.main(Main.scala:109)
at com.testpackage.Main.main(Main.scala)    
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)     
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

我正在使用 ojdbc7.jar 进行 jdbc 连接。 有什么不同的方法可以将数组传递给准备好的语句吗?

【问题讨论】:

    标签: java oracle scala jdbc


    【解决方案1】:

    Oracle 数据库 JDBC 驱动程序不支持 Connection.createArrayOf,因为 Oracle 数据库不支持匿名数组类型。类型 ARRAY OF FOO 是匿名类型。尽管基本类型有,但数组类型没有名称。 Oracle 数据库不支持匿名数组类型。你必须定义一个命名类型

    TYPE ARRAY_OF_FOO IS TABLE OF FOO;
    

    然后你可以通过调用来创建一个数组

    oracleConnection.createOracleArray("ARRAY_OF_FOO", elements);
    

    【讨论】:

    • 非常感谢您的回答!我真的不明白“我不会回答你问的问题”怎么能被接受。提供替代更好的解决方案或批评其他问题很好,但我真的认为应该回答实际问题,因为为你实际面临的问题找到实际问题只是发现“我不会回答这个问题”是很痛苦的你问过”。再次感谢您提供实际答案,您对我帮助很大。
    【解决方案2】:

    我不会回答您提出的问题(“如何将数组传递给准备好的语句”),因为即使您知道如何传递数组,您的代码很可能仍然不会工作。

    问题在于,使用 JDBC 时,您无法将包含两个值 ("1165006001","1165006002") 的数组传递到查询中

    select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in (?)
    

    并期望它被数据库解释为

    select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in ('1165006001','1165006002')
    

    在我看来你想要它。

    如果您可以传入该数组,则查询将返回列CMF_PPK_NBR 包含具有这两个值的嵌套表的所有行。 Oracle 会将数组解释为一个值,而不是两个值。我猜该列的类型为 VARCHAR2,因此当 Oracle 尝试将字符串数组与单个字符串进行比较时,您只会遇到类型错误。

    如果要在IN 子句中传递多个值,那么最简单的方法是构建一个带有多个? 标记的SQL 字符串,并分别设置参数的值。换句话说,对于上面的示例,两个参数的 SQL 字符串将是

    select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in (?, ?)
    

    您将有两次调用prep.setString(...),每个数组元素调用一次。同样,如果数组中有 5 个项目,您将构建一个带有 5 个 ? 标记的 SQL 字符串,并调用 prep.setString(...) 5 次,依此类推。

    【讨论】:

    • 这个答案具有误导性,因为有ways to pass arrays - 您可以使用CREATE TYPE StringList IS TABLE OF VARCHAR2(20) 创建一个集合,然后SELECT * FROM DUAL WHERE DUMMY MEMBER OF ? 您可以使用StringList 类型将字符串数组作为StringList 类型传递@java 类和oracle.jdbc.OracleCallableStatement.setARRAYAtName( String, ARRAY ) 方法。如果要使用IN 运算符,则可以使用表集合表达式:SELECT * FROM DUAL WHERE DUMMY IN (SELECT COLUMN_VALUE FROM TABLE(?))
    • @MT0:我并不是说没有办法传递数组,我只是说上面的方法是最简单的。此外,如果提问者没有在数据库中创建类型的权限怎么办?
    • 有没有人有那个迭代的例子,基于数组的大小?
    【解决方案3】:

    没有完全好的方法可以做到这一点,但仍然存在两种合理的方法。

    使用手工制作的in (?,...) 子句。

    solution is explained here。这个想法是添加与数组元素一样多的?s,并单独绑定每个项目。这让您放心,因为值将被正确转换、转义等。

    这种方式违背了准备语句的目的,除非您的数组通常大小相同。

    如果数组中有很多项,也可能超出允许的查询长度。

    使用强制转换并将数组作为字符串传递。

    解决方案(对于 PL/SQL)是explained here,但适用于一般 SQL 语句。它归结为使用像

    这样的子句
    ...in (select cast(in_list(?) as some_table_type) from dual)
    

    这里的参数作为varchar2传递,就像"1, 2, 3"一样,被解析为内存表,并从中选择,都在in子句中。

    这使您可以进行固定长度的查询,并可能有效地重用准备好的语句。它还允许您传递数组中的大量项目。

    OTOH,要求您将数据作为字符串连接并传递, 这可能会导致 SQL 注入。 我仍然认为它是如果您的数组值是数字,则安全。

    【讨论】:

      猜你喜欢
      • 2017-12-07
      • 2011-04-18
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      相关资源
      最近更新 更多