postgres的最新Java JDBC驱动程序声称本机支持UUID;针对Postgres9.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);
}
}
什么东西?实际数据库中是否需要一些魔法符文来祝福这种转换?
tl;dr
myPreparedStatement.setObject(
… ,
java.util.UUID.randomUUID()
)
详细信息
(a) 向我们展示您的代码。
CCD_ 1在传递CCD_。您的代码中可能存在其他问题。
(b) 请参阅我的博客文章《从JDBC到Postgres的UUID值》,了解一些讨论和示例代码。
// 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上使用setObject
和getObject
方法来跨越Java之间的鸿沟移动UUID↔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值。有关说明,请参阅我的博客。
顺便说一下…
如果我知道如何请求JDBC专家组或JSR团队让JDBC知道UUID,我当然会的。他们正是为JSR310中定义的新日期时间类型:日期和时间API做这件事。
同样,如果我知道如何向SQL标准委员会申请添加UUID的数据类型,我会的。但显然,该委员会比苏联政治局更隐秘,速度也比冰川慢。
我使用以下方法将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。
这对我使用org.postgresql.postgresql42.2.5 有效
myPreparedStatement.setObject(4, UUID.randomUUID(),java.sql.Types.OTHER)
在没有java.sql.Types.OTHER的情况下,我得到了一个错误
尝试
.setParameter("uuid", uuid, PostgresUUIDType.INSTANCE);