web-dev-qa-db-fra.com

Comment puis-je insérer un objet JSON dans Postgres en utilisant Java préparéStatement?

Je ne parviens pas à insérer un objet JSON dans ma base de données Postgres v9.4. J'ai défini la colonne appelée "evtjson" comme étant le type json (et non jsonb).

J'essaie d'utiliser une instruction préparée dans Java (jdk1.8) pour insérer un objet Json (construit à l'aide de bibliothèques JEE javax.json) dans la colonne, mais je continue à courir dans les erreurs SQLException.

Je crée l'objet JSON en utilisant:

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

Ensuite, je passe cet objet en tant que paramètre à une autre méthode pour l'écrire dans la base de données à l'aide d'une instruction préparée. (avec plusieurs autres domaines) En tant que:

pStmt.setObject(11, dtlRec);

À l'aide de cette méthode, je reçois le message d'erreur suivant:

org.postgresql.util.PSQLException: aucune extension hstore n'est installée. à org.postgresql.jdbc.PgPreparedStatement.setMap (PgPreparedStatement.Java:553) à org.postgresql.jdbc.PgPreparedStatement.setObject (PgPreparedStatement.Java:1036)

J'ai aussi essayé:

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

Qui produisent une erreur différente:

Evénement JSON: {"New MbrID": 29}

SQLException: ERREUR: la colonne "evtjson" est de type json mais l'expression est de type caractère variable

Astuce: vous devrez réécrire ou convertir l'expression.

Mais au moins, cela me dit que la base de données reconnaît la colonne en tant que type JSON. J'ai essayé d'installer l'extension hstore, mais il m'a ensuite dit que ce n'était pas un objet hstore.

OracleDocs montre un certain nombre de méthodes différentes pour définir la valeur du paramètre dans le readyStatement, mais je préfère ne pas les essayer toutes si quelqu'un connaît la réponse. ( http://docs.Oracle.com/javase/8/docs/api/Java/sql/PreparedStatement.html ) Ces éléments font également référence à un paramètre supplémentaire, SQLType, mais je n'en trouve aucun. référence à ceux-ci.

Devrais-je essayer setAsciiStream? CharacterStream? CLOB?

39

Ce comportement est assez gênant puisque les chaînes JSON sont acceptées sans problème lorsqu'elles sont utilisées comme chaînes littérales dans les commandes SQL.

Il existe déjà un problème pour cela dans le référentiel Github du pilote postgres (même si le problème semble être le traitement côté serveur).

En plus d'utiliser un transtypage (voir la réponse de @a_horse_with_no_name) dans la chaîne SQL, l'auteur du problème propose deux solutions supplémentaires:

  1. Utiliser un paramètre stringtype=unspecified dans l'URL/options de connexion JDBC.

Cela indique à PostgreSQL que tous les paramètres text ou varchar sont en fait de type inconnu, ce qui permet de déduire leurs types plus librement.

  1. Envelopper le paramètre dans un org.postgresql.util.PGobject:
 PGobject jsonObject = new PGobject();
 jsonObject.setType("json");
 jsonObject.setValue(yourJsonString);
 pstmt.setObject(11, jsonObject);
45
wero

Vous pouvez le faire comme ça et vous avez juste besoin de la chaîne json:

Modifiez la requête en:

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

Et définissez le paramètre en tant que chaîne.

pStmt.setString(1, json);
23
Tiago

Passer le JSON en tant que chaîne est la bonne approche, mais comme le message d'erreur le dit, vous devez transtyper le paramètre de l'instruction INSERT en une valeur JSON. :

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

Ensuite, vous pouvez utiliser pStmt.setString(11, dtlRec.toString()) pour transmettre la valeur

12

Vous avez deux options:

  1. Utilisez statement.setString (jsonStr), puis gérez la conversion dans l'instruction 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);

`Personnellement, je préfère ce dernier car la requête est plus propre

5
pedram bashiri

PostgreSQL est excessivement, extrêmement agaçant quant aux conversions de types de données. Il ne convertira pas implicitement le texte même en valeurs de type texte telles que xml et json.

de sorte que la solution originale dans cette réponse contourne la validation JSON par

create cast (CHARACTER VARYING en json) sans fonction en tant qu'implicite;

here CHARACTER VARYING vous essayez en fait de passer à votre objet instruction préparé.

0
deadpool

Au lieu de transmettre l'objet json, transmettez sa valeur de chaîne et transmettez-la à json dans la requête. Exemple:

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

String yourJsonString = someJsonObject.toString();

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

cela a fonctionné pour moi.

0
Komal Thakur