Postgres UUID JDBC无法正常工作

时间:2013-07-31 11:43:57

标签: java postgresql jdbc pg-jdbc

postgres的最新Java JDBC驱动程序声称本机支持UUID;与Postgres 9.2(mac)合作。

实际上,当使用PreparedStatement时,我可以单步执行驱动程序代码,甚至可以走路 通过AbstractJdbc3gStatement.java中的专用'setUuid'函数。根据所有迹象,它应该“正常工作”。

然而,它不起作用。数据库收回了一个错误,我收到了错误:

Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = bytea
  Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
  Position: 139
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157) ~[postgresql-9.2-1002.jdbc4.jar:na]

是的,确实,JDBC驱动程序中的setUuid会将其作为bytea发送:

private void setUuid(int parameterIndex, UUID uuid) throws SQLException {
        if (connection.binaryTransferSend(Oid.UUID)) {
            byte[] val = new byte[16];
            ByteConverter.int8(val, 0, uuid.getMostSignificantBits());
            ByteConverter.int8(val, 8, uuid.getLeastSignificantBits());
            bindBytes(parameterIndex, val, Oid.UUID);
        } else {
            bindLiteral(parameterIndex, uuid.toString(), Oid.UUID);
        }
    }

是什么给出的? 实际数据库中是否需要一些魔法符文来祝福这种转换?

4 个答案:

答案 0 :(得分:28)

TL;博士

myPreparedStatement.setObject( 
    … , 
    java.util.UUID.randomUUID()
)

详细

(a)向我们展示您的代码。

传递PreparedStatement::setObject时,

java.util.UUID确实有效。您的代码中可能还有其他一些问题。

(b)请参阅我的博客文章UUID Values From JDBC to Postgres,了解一些讨论和示例代码。

// Generate or obtain data to store in database.
java.util.UUID uuid = java.util.UUID.randomUUID(); // Generate a random UUID. 
String foodName = "Croissant";
// JDBC Prepared Statement.
PreparedStatement preparedStatement = conn.prepareStatement( "INSERT INTO food_ (pkey_, food_name_  ) VALUES (?,?)" );
int nthPlaceholder = 1; // 1-based counting (not an index).
preparedStatement.setObject( nthPlaceholder++, uuid ); 
preparedStatement.setString( nthPlaceholder++, foodName ); 
// Execute SQL.
if ( !( preparedStatement.executeUpdate() == 1 ) ) { 
  // If the SQL reports other than one row inserted…
  this.logger.error( "Failed to insert row into database." );
}

(c)我不确定你的意思

  

postgres的最新Java JDBC驱动程序声称本机支持UUID

哪个司机? Postgres至少有两个开源JDBC驱动程序,current/legacy one和一个新的重写"next generation" one。还有其他商业驱动因素。

“本地”?你能链接到你读过的文件吗? SQL规范没有UUID的数据类型(遗憾的是☹),因此JDBC spec没有UUID的数据类型。作为一种解决方法,Postgres的JDBC驱动程序使用PreparedStatement上的setObjectgetObject方法将UUID移到Java↔SQL↔Postgres之间的鸿沟上。请参阅上面的示例代码。

正如PreparedStatement JDBC doc所说:

  

如果需要任意参数类型转换,则方法setObject应与目标SQL类型一起使用。

也许通过“本机”,您将Postgres对UUID的本机支持混淆为具有UUID数据类型的JDBC的数据类型。 Postgres确实支持UUID作为数据类型,这意味着该值存储为128位而不是多次存储,如果它存储为ASCII或Unicode十六进制字符串。而本地化也意味着Postgres知道如何在该类型的列上构建索引。

上面提到的我的博客文章的重点是,我很惊讶地解决了在Java ↔ SQL ↔ Postgres之间弥合这个鸿沟的简单程度。在我第一次没有受过教育的尝试中,我工作太辛苦了。


关于Postgres支持UUID的另一个注释... Postgres知道如何存储,索引和检索现有的UUID值。要生成 UUID值,您必须启用Postgres扩展(插件)uuid-ossp。此扩展包装a library provided by The OSSP Project以生成各种UUID值。请参阅my blog for instructions


顺便说一句......

如果我知道如何请求JDBC专家组或JSR团队让JDBC知道UUID,我当然会。他们正在为JSR 310: Date and Time API中定义的新日期时间类型执行此操作。

同样,如果我知道如何请求SQL标准委员会添加数据类型的UUID,我会的。但显然,委员会比苏联政治局更隐秘,而且比冰川慢。

答案 1 :(得分:13)

我使用以下方法将UUID和其他对象添加到postgres:

 PGobject toInsertUUID = new PGobject();
 toInsertUUID.setType("uuid");
 toInsertUUID.setValue(uuid.toString());
 PreparedStmt stmt = conn.prepareStatement(query);
 stmt.setObject(placeHolder,toInsertUUID);
 stmt.execute();

这样你就可以阻止自己进行类型转换。这段代码对我来说非常适合,例如甚至是json。

答案 2 :(得分:1)

这对于我使用org.postgresql.postgresql 42.2.5有用

myPreparedStatement.setObject(4, UUID.randomUUID(),java.sql.Types.OTHER)

没有java.sql.Types.OTHER我出现了错误

答案 3 :(得分:0)

尝试

.setParameter("uuid", uuid, PostgresUUIDType.INSTANCE);