web-dev-qa-db-ja.com

Java prepareStatementを使用してJSONオブジェクトをPostgresに挿入するにはどうすればよいですか?

JSONオブジェクトをpostgres v9.4 DBに挿入するのに苦労しています。 「_evtjson」という列をjson型(jsonbではない)として定義しました。

Java(jdk1.8)の準備されたステートメントを使用してJsonオブジェクト(JEE javax.jsonライブラリを使用して構築された)を列に挿入しようとしていますが、SQLExceptionエラーが発生し続けます。

以下を使用してJSONオブジェクトを作成します。

JsonObject mbrLogRec = Json.createObjectBuilder().build();
…
mbrLogRec = Json.createObjectBuilder()
                .add("New MbrID", newId)
                .build();

次に、このオブジェクトを別のメソッドにパラメーターとして渡し、準備されたステートメントを使用してDBに書き込みます。 (他のいくつかのフィールドとともに)As:

pStmt.setObject(11, dtlRec);

この方法を使用すると、次のエラーが表示されます。

org.postgresql.util.PSQLException:hstore拡張機能がインストールされていません。 org.postgresql.jdbc.PgPreparedStatement.setMap(PgPreparedStatement.Java:553)at org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.Java:1036)

私も試しました:

pStmt.setString(11, dtlRec.toString());
pStmt.setObject(11, dtlRec.toString());

別のエラーが発生します:

イベントJSON:{"新しいMbrID":29}

SQLException:エラー:列 "evtjson"はjson型ですが、expressionは可変文字型です

ヒント:式を書き換えるか、キャストする必要があります。

しかし、少なくともこれは、DBが列をJSON型として認識していることを示しています。 hstore拡張機能をインストールしようとしましたが、hstoreオブジェクトではないことを教えてくれました。

OracleDocsでは、preparedStatementにパラメータ値を設定するための様々なメソッドが示されていますが、答えがわかっている場合はすべて試してみたくはありません。 ( http://docs.Oracle.com/javase/8/docs/api/Java/sql/PreparedStatement.html )これらは追加のパラメーターSQLTypeを参照していますが、何も見つかりませんこれらへの参照。

setAsciiStreamを試す必要がありますか? CharacterStream? CLOB?

39

JSONコマンドはSQLコマンドでリテラル文字列として使用される場合、問題なく受け入れられるため、この動作は非常に面倒です。

既にpostgresドライバーのGithubリポジトリに issue があります(問題がサーバー側の処理であると思われる場合でも)。

Sql文字列でキャスト(@a_horse_with_no_nameの回答を参照)を使用することに加えて、問題の作成者は2つの追加ソリューションを提供します。

  1. JDBC接続URL /オプションでパラメーターstringtype=unspecifiedを使用します。

これにより、すべてのテキストまたはvarcharパラメーターは実際には不明なタイプであり、より自由にタイプを推測できるようになります。

  1. パラメーターをorg.postgresql.util.PGobjectでラップします。
 PGobject jsonObject = new PGobject();
 jsonObject.setType("json");
 jsonObject.setValue(yourJsonString);
 pstmt.setObject(11, jsonObject);
45
wero

このようにすることができ、json文字列が必要です:

クエリを次のように変更します。

String query = "INSERT INTO table (json_field) VALUES (to_json(?::json))"

パラメータを文字列として設定します。

pStmt.setString(1, json);
23
Tiago

JSONを文字列として渡すのが正しいアプローチですが、エラーメッセージが示すように、INSERTステートメントのparameterJSON値にキャストする必要があります。

insert into the_table
   (.., evtjson, ..) 
values 
   (.., cast(? as json), ..)

次に、pStmt.setString(11, dtlRec.toString())を使用して値を渡すことができます

12

次の2つのオプションがあります。

  1. Statement.setString(jsonStr)を使用して、sqlステートメントで変換を処理します。

`

PreparedStatement statement = con.prepareStatement("insert into table 
 (jsonColumn) values (?::json)");
 statement.setString(1, jsonStr);

2. Another option is to use PGobject to create a custom value wrapper.

PGobject jsonObject = new PGobject();
 PreparedStatement statement = con.prepareStatement("insert into table 
 (jsonColumn) values (?)");
 jsonObject.setType("json");
 jsonObject.setValue(jsonStr);
 statement.setObject(1, jsonObject);

`個人的にはクエリがクリーンなので後者を好む

5
pedram bashiri

PostgreSQLは、データ型の変換について非常に面倒です。 xmlやjsonなどのテキストのような値にでも暗黙的にテキストをキャストしません。

したがって、この回答の元のソリューションは、JSON検証をバイパスします

暗黙的な関数なしでキャストを作成します(jsonとしての文字可変);

here CHARACTER VARYINGは、実際に準備済みステートメントオブジェクトに渡そうとしているものです。

0
deadpool

Jsonオブジェクトを渡す代わりに、その文字列値を渡し、クエリでjsonにキャストします。例:

JSONObject someJsonObject=..........

String yourJsonString = someJsonObject.toString();

String query = "INSERT INTO table (json_field) VALUES (to_json(yourJsonString::json))";

これは私のために働いた。

0
Komal Thakur