【问题标题】:Postgres UUID JDBC not workingPostgres UUID JDBC 不工作
【发布时间】:2013-07-31 22:08:26
【问题描述】:

用于 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 确实将其作为字节发送:

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);
        }
    }

什么给了? 实际数据库中是否需要一些魔法符文来加持这种转换?

【问题讨论】:

  • 您可以发布您尝试运行的实际 PreparedStatement 吗?

标签: java postgresql jdbc pg-jdbc


【解决方案1】:

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

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

没有 java.sql.Types.OTHER 我得到一个错误

【讨论】:

  • 非常感谢,我一直在努力寻找正确的解决方案。
【解决方案2】:

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 数据类型,我会的。但显然那个委员会比苏联政治局更隐秘,比冰川还慢。

【讨论】:

  • > 那个委员会比苏联政治局更隐秘,比冰川还慢。 ...年度评论!!!
【解决方案3】:

试试

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

【讨论】:

  • PostgresUUIDType.INSTANCE 是从哪里来的,好像是Hibernate 类?
  • org.hibernate.type
【解决方案4】:

我使用以下方法将 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。

【讨论】:

  • PGobject从何而来?
  • @PaulTaylor,org.postgresql.util.PGobject 来自 PostgreSQL JDBC 驱动,org.postgresql:postgresql
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 2018-04-08
  • 2011-06-10
  • 1970-01-01
  • 2019-07-01
  • 2017-01-19
  • 2010-10-20
相关资源
最近更新 更多