17

用于 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

4 回答 4

33

tl;博士

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

细节

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

PreparedStatement::setObject通过 a 时确实有效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 驱动程序,一个是当前的/旧的,一个是新的重写“下一代”驱动程序。还有其他商业驱动因素。

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

正如PreparedStatement JDBC 文档所说:

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

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

上面提到的我的博客文章的重点是,我对跨越Java ↔ SQL ↔ Postgres. 在我第一次没有受过教育的尝试中,我工作太努力了。


关于 Postgres 支持 UUID 的另一个注意事项…… Postgres 知道如何存储、索引和检索现有的 UUID 值。要生成UUID 值,您必须启用 Postgres 扩展(插件)uuid-ossp。这个扩展包装了一个由 OSSP 项目提供的库,用于生成各种 UUID 值。有关说明,请参阅我的博客


顺便说一句……</p>

如果我知道如何请求 JDBC 专家组或 JSR 团队让 JDBC 了解 UUID,我当然会。他们正在为JSR 310 中定义的新日期时间类型做这件事:日期和时间 API

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

于 2013-11-03T09:45:32.687 回答
15

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

于 2014-03-27T08:16:40.613 回答
12

This worked for me using the org.postgresql.postgresql 42.2.5

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

Without java.sql.Types.OTHER I got an error

于 2019-01-16T10:06:48.107 回答
0

尝试

.setParameter("uuid", uuid, PostgresUUIDType.INSTANCE);
于 2016-12-15T15:07:39.200 回答