如何将String []参数设置为本机查询?

时间:2012-08-20 17:25:42

标签: java postgresql eclipselink jpql

这是我的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调用我的函数。

4 个答案:

答案 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.3bug 361701

看来你可能必须为EclipseLink实现自己的类型处理程序来覆盖它的行为。要通过PgJDBC正确设置数组参数,您必须使用:

    Array sqlArray = conn.createArrayOf("text", strArray);
    pstmt.setArray(1, sqlArray);
    pstmt.executeUpdate();

...其中connpstmt分别是java.sql.ConnectionPreparedStatementstrArrayString[]个实例。< / p>

请参阅Custom data types in the eclipselink wiki

另一方面,考虑到createArrayOf的存在,使用字符串类型名称来指定java.sql.Types中数组的数据类型似乎有点疯狂。它使便携性变得更加困难;上面的代码不会在(例如)Oracle上运行,因为Oracle希望VARCHAR而不是text作为类型名称。


注意:单元测试org/postgresql/test/jdbc2/ArrayTest.javaArrayTest.testSetArray(),在第166行测试:

    pstmt.setObject(1, arr);
    pstmt.executeUpdate();

...但arr的类型为java.sql.Array,而不是int[]。它是JDBC数组类型,而不是常规Java数组。

答案 1 :(得分:6)

我很晚才回答。

这个解决方案是一种使用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 :(得分: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时遇到了这个错误