web-dev-qa-db-ja.com

Postgres UUIDJDBCが機能しない

最新のJava postgres用の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はそれを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);
        }
    }

何が得られますか?この変換を祝福するために実際のデータベースに必要な魔法のルーンはありますか?

13
user340535

tl; dr

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

詳細

(a)コードを表示してください。

PreparedStatement::setObjectJava.util.UUID を渡すと機能します。コードに他の問題がある可能性があります。

(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)どういう意味かわかりません

最新のJava postgres用のJDBCドライバーは、UUIDをネイティブにサポートすると主張しています

どのドライバー? Postgresには少なくとも2つのオープンソースJDBCドライバーがあります。 現在/レガシーのもの と新しい書き換え 「次世代」のもの です。そして、他の商用ドライバーもあります。

「生まれつき」?読んだドキュメントにリンクできますか? SQL仕様には [〜#〜] uuid [〜#〜] (残念ながら☹)のデータ型がないため、 JDBC仕様 にはUUIDのデータ型がありません。回避策として、PostgresのJDBCドライバーはPreparedStatementでsetObjectメソッドとgetObjectメソッドを使用して、UUIDをJava↔SQL↔Postgresの間の溝を越えて移動します。上記のサンプルコード。

PreparedStatement JDBC doc が言うように:

任意のパラメーター型の変換が必要な場合は、メソッドsetObjectをターゲットSQL型で使用する必要があります。

おそらく「ネイティブに」、Postgresのデータ型としてのUUIDのネイティブサポートを、UUIDデータ型を持つJDBCと混同しました。 Postgresは確かにデータ型としてUUIDをサポートしています。つまり、値はASCIIまたはUnicodeの16進文字列として保存された場合の複数倍ではなく128ビットとして保存されます。また、ネイティブであることも意味します。 Postgresがそのタイプの列にインデックスを作成する方法を知っていることを意味します。

上記の私のブログ投稿のポイントは、Java ↔ SQL ↔ Postgres間のその溝を埋めるのがいかに簡単であるかに嬉しい驚きを感じたことです。私の最初の教育を受けていない試みでは、私はあまりにも一生懸命働いていました。


UUIDをサポートするPostgresに関する別の注意事項…Postgresは、既存のUUID値を格納、インデックス付け、および取得する方法を知っています。 generate UUID値を得るには、Postgres拡張機能(プラグイン)を有効にする必要があります uuid-ossp 。この拡張機能は、さまざまな種類のUUID値を生成するために OSSPプロジェクトによって提供されるライブラリ をラップします。 手順については私のブログ を参照してください。


ところで…

JDBCエキスパートグループまたはJSRチームにJDBCにUUIDを認識させる方法を知っていれば、確かにそうします。 JSR 310:Date and Time API で定義されている新しい日時タイプに対してまさにそれを行っています。

同様に、SQL標準委員会にUUIDのデータ型を追加するように請願する方法を知っていれば、そうします。しかし、どうやらその委員会はソビエトの政治局よりも秘密主義であり、氷河よりも遅い。

28
Basil Bourque

次のアプローチを使用して、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でさえ、いつでも完璧に機能しました。

13
Nischal Hp

これは、org.postgresql.postgresql42.2.5を使用して私のために機能しました

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

Java.sql.Types.OTHERがないと、エラーが発生しました

4

試してみてください

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