如何将 String[] 参数设置为本机查询?
Posted
技术标签:
【中文标题】如何将 String[] 参数设置为本机查询?【英文标题】:How can I set a String[] parameter to a native query? 【发布时间】:2012-08-16 01:12:11 【问题描述】:这是我的 PostgreSQL 函数:
salvarArquivoGeometricoCasoZeroPOINT
(dimensao text,tableName text,tuplas text[],srid text)
它有一个 text[]
参数,我想从我的 JPQL 向它传递一个 Java String[]
:
public String salvarGeometriaCaso0(String[] tuplas,FileDto arquivo)
Query query =
em().createNativeQuery("select
salvarArquivoGeometricoCasoZeroPOINT(?1,?2,?3,?4)");
query.setParameter(1,arquivo.getGeo());//String
query.setParameter(2,arquivo.getTable());/String
query.setParameter(3,tuplas);//String[]
query.setParameter(4,arquivo.getSrid());//String
return (String) query.getSingleResult();//function returns a Text, so cast to String
上述代码失败,异常:
ERROR] Internal Exception: org.postgresql.util.PSQLException: Can not infer a SQL
type to use for an instance of [Ljava.lang.String;.
Use setObject () with an explicit Types value to specify the type to use.
所以我不确定如何从 EclipseLink 调用我的函数。
【问题讨论】:
您是否尝试过“[使用]setObject ()
使用明确的Types
值来指定要使用的类型?”
你能告诉我怎么做吗?
您可以在PreparedStatement
上调用setObject()
而不是query.setParameter(3, tuplas)
。 docs.oracle.com/javase/7/docs/api/java/sql/…
但我使用的是 EclipseLink。我必须遵循一些模式,我不能使用 PreparedStatement。
哪个 EclipseLink 版本?哪个 PgJDBC 版本?我以为 EclipseLink 和 PgJDBC 理解 String[]
映射到 text[]
。
【参考方案1】:
我很晚才回答。
这个解决方案是一种使用 postgreSQL 内置函数的解决方法,它绝对对我有用。
reference blog
1) 将字符串数组转换为逗号分隔的字符串
如果您使用的是 Java8,这很容易。其他选项是here
String commaSeparatedString = String.join(",",stringArray); // Java8 feature
2) PostgreSQL 内置函数 string_to_array()
你可以找到其他的postgreSQL数组函数here
// tableName ( name text, string_array_column_name text[] )
String query = "insert into tableName(name,string_array_column_name ) values(?, string_to_array(?,',') )";
int[] types = new int[] Types.VARCHAR, Types.VARCHAR;
Object[] psParams = new Object[] "Dhruvil Thaker",commaSeparatedString ;
jdbcTemplate.batchUpdate(query, psParams ,types); // assuming you have jdbctemplate instance
【讨论】:
【参考方案2】:通过将 String[] 类型的 Java 数组传递给 PreparedStatement.setObject(...)
进行测试会导致您报告的行为。 PgJDBC 似乎不接受 Java 数组作为 PreparedStatement.setObject()
的参数,无论是否带有 Types.ARRAY
参数。
合规
JDBC 规范 16.5 "Array Objects" 表明 JDBC Array
部分存在,因此客户端不必将大数组复制到内存中,它们可以通过引用来使用。我不太确定 JDBC 驱动程序是否需要接受原始 Java 数组作为参数。所有规范代码都引用了java.sql.Array
,并且规范清楚地表明,数组是通过附录 B 和其他地方的Array
接口映射的。在快速搜索/阅读中,我发现没有提到将 byte[]
以外的原始 Java 数组作为参数传递或将它们作为结果返回。
但是,在 §16.5.4 中,JDBC4.2 草案规范如下:
A Java array may be passed as an input parameter by calling the method
PreparedSatement.setObject.
尽管所有其他代码都引用了Array
对象。他们是指“Java 数组”中的Array
吗?还是他们的意思是像 String[]
这样的原始原生 Java 数组?
在我看来,客户端应该通过Connection.createArrayOf(...)
使用java.sql.Array
接口,所以EclipseLink 可能做错了。
怎么办
尝试将 EclipseLink 更新到 2.4,希望它使用the commonly specified method of passing arrays to JDBC via a java.sql.Array object。
您可能还需要使用 EclipseLink 扩展 @Array
来注释映射。另见this forum thread re 2.3 和bug 361701。
看来您可能必须为 EclipseLink 实现自己的类型处理程序才能覆盖其行为。要通过 PgJDBC 正确设置数组参数,您必须使用:
Array sqlArray = conn.createArrayOf("text", strArray);
pstmt.setArray(1, sqlArray);
pstmt.executeUpdate();
...其中conn
和pstmt
分别是java.sql.Connection
和PreparedStatement
,strArray
是String[]
实例。
见Custom data types in the eclipselink wiki。
另一方面,考虑到java.sql.Types
的存在,使用字符串类型名称来指定createArrayOf
中的数组数据类型似乎有点疯狂。它使便携性变得更加困难;上面的代码不会在(比如说)Oracle 上运行,因为 Oracle 想要 VARCHAR
而不是 text
作为类型名称。
注意:单元测试org/postgresql/test/jdbc2/ArrayTest.java
有ArrayTest.testSetArray()
,在第 166 行测试:
pstmt.setObject(1, arr);
pstmt.executeUpdate();
...但是arr
的类型是java.sql.Array
,而不是int[]
。它是 JDBC 数组类型,而不是常规的 Java 数组。
【讨论】:
更新 eclipseLink 不起作用。唯一的方法是使用纯 JDBC【参考方案3】:EclipseLink 似乎无法修复@Craig Ringer 提到的bug 361701.。
将 String[] 作为参数传递的唯一方法是使用没有 EclipseLink 的 JDBC。检查代码。
Connection con = ConnectionHelper.getConnection();
Array tArray = con.createArrayOf("text", tuplas);
PreparedStatement pstm =
con.prepareStatement("select salvarArquivoGeometricoCasoZeroPOINT(?,?,?,?)");
pstm.setString(1,arquivo.getGeoType());
pstm.setString(2,arquivo.getTable());
pstm.setArray(3,tArray);
pstm.setString(4,arquivo.getSrid());
rs = pstm.executeQuery();
ConnectionHelper 这是我的 java.sql.Connection 类。
感谢你们的帮助:@Craig Ringer 和 @Matt Ball,谢谢。
【讨论】:
我想您也可以使用自定义数据类型工具为数组实现自己的 EclipseLink 数据类型处理程序。不过,下拉到普通的 JDBC 可能更容易。【参考方案4】:我在不小心使用jdbcTemplate.update
而不是jdbcTemplate.batchUpdate
时遇到了这个错误
【讨论】:
以上是关于如何将 String[] 参数设置为本机查询?的主要内容,如果未能解决你的问题,请参考以下文章