这是我的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调用我的函数。
答案 0 :(得分:7)
通过将String []类型的Java数组传递给PreparedStatement.setObject(...)
进行测试会导致您报告的行为。似乎PgJDBC不接受Java数组作为PreparedStatement.setObject()
的参数,包含或不包含Types.ARRAY
参数。
JDBC规范, 16.5“数组对象”,表明JDBC Array
部分存在,因此客户端不必将大数组复制到内存中,它们可以被参考。我不太确定JDBC驱动程序是否需要接受原始Java数组作为参数。所有规范代码都引用java.sql.Array
,规范明确规定数组是通过附录B和其他地方的Array
接口映射的。在快速搜索/阅读中,我发现 no 提及将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 1”的Array
吗?或者它们是指原始的本机Java数组,如String[]
?
在我看来,客户端应该通过java.sql.Array
使用Connection.createArrayOf(...)
接口,因此EclipseLink可能做错了。
尝试将EclipseLink更新为2.4,希望它使用the commonly specified method of passing arrays to JDBC via a java.sql.Array object。
您可能还需要使用@Array
(EclipseLink扩展)注释映射。另请参阅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[]
个实例。< / p>
请参阅Custom data types in the eclipselink wiki。
另一方面,考虑到createArrayOf
的存在,使用字符串类型名称来指定java.sql.Types
中数组的数据类型似乎有点疯狂。它使便携性变得更加困难;上面的代码不会在(例如)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数组。
答案 1 :(得分:6)
我很晚才回答。
这个解决方案是一种使用postgreSQL内置函数的解决方法,这绝对适用于我。
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 :(得分:1)
似乎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,谢谢。
答案 3 :(得分:0)
我不小心使用jdbcTemplate.update
而不是jdbcTemplate.batchUpdate
时遇到了这个错误