尝试将数组传递给预准备语句时,Oracle jdbc"createArray"会抛出"不支持的功能"异常

sra*_*mar 7 java oracle scala jdbc

我试图通过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))

}
Run Code Online (Sandbox Code Playgroud)

但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)
Run Code Online (Sandbox Code Playgroud)

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

Luk*_*ard 7

我不打算回答你问过的问题("我怎样才能将数组传递给预备语句"),因为即使你能弄清楚如何传递数组,你的代码很可能仍然无效.

问题是,使用JDBC,您无法将两个值的数组传递("1165006001","1165006002")给查询

select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in (?)
Run Code Online (Sandbox Code Playgroud)

并期望它被数据库解释为

select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in ('1165006001','1165006002')
Run Code Online (Sandbox Code Playgroud)

因为在我看来你想要它.

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

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

select * from SOA_WEB_USER.VOPEX where CMF_PPK_NBR in (?, ?)
Run Code Online (Sandbox Code Playgroud)

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

  • 这个答案具有误导性,因为存在[传递数组的方式](/sf/answers/2428984001/)-您可以使用“创建类型为StringCHAR表类型为VARCHAR2(20)的表,然后选择”来创建一个集合。 *从?的双重虚拟成员中,您可以使用oracle.sql.ARRAY Java类和oracle.jdbc.OracleCallableStatement.setARRAYAtName(String,ARRAY)方法将字符串数组作为StringList类型传递。 。如果要使用IN运算符,则可以使用表集合表达式:SELECT * FROM DUAL WHERE DUMMY IN(SELECT COLUMN_VALUE FROM TABLE(?))。 (2认同)

900*_*000 5

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

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

解决方案在此说明。这个想法是添加与?数组元素一样多的s,并分别绑定每个项目。这将使您放心,因为值将被正确转换,转义等。

除非您的数组通常具有相同的大小,否则这种做法会破坏准备语句的目的。

如果数组中有很多项目,那么您也可以用完所允许的查询长度。

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

该解决方案(针对PL / SQL)在此处进行了说明,但适用于常规SQL语句。归结为使用类似

...in (select cast(in_list(?) as some_table_type) from dual)
Run Code Online (Sandbox Code Playgroud)

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

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

它(OTOH)要求您连接并以字符串形式传递数据,这有可能导致SQL注入。如果您的数组值为数字,我仍然认为它是安全的。


小智 5

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

TYPE ARRAY_OF_FOO IS TABLE OF FOO;
Run Code Online (Sandbox Code Playgroud)

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

oracleConnection.createOracleArray("ARRAY_OF_FOO", elements);
Run Code Online (Sandbox Code Playgroud)