Обсуждение: Inserting JSON via Java PreparedStatment

Поиск
Список
Период
Сортировка

Inserting JSON via Java PreparedStatment

От
Curt Huffman
Дата:

Hello!

I’m struggling to insert a JSON object into my postgres v9.4 DB. I have defined the column called "evtjson" as type json. (not jsonb)
I am trying to use a prepared statement in Java (jdk1.8) to insert a Json object (built using JEE javax.json libraries) into the column, but I keep running into SQLException errors.  

I'm using JDBC 9.4.1208

I create the JSON object using:

JsonObject mbrLogRec = Json.createObjectBuilder().build();

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

Then I pass this object as a parameter to another method to write it to the DB using a prepared statement. (along with several other fields) As:

pStmt.setObject(11, dtlRec);

Using this method, I receive the following error:

at org.postgresql.util.PSQLException: No hstore extension installed. 

at org.postgresql.jdbc.PgPreparedStatement.setMap(PgPreparedStatement.java:553) 

at org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1036)

I did try installing the hstore extension, but it then told me that it was not an hstore object.

I have also tried:

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

Which produce a different error:

Event JSON: {"New MbrID":29}

SQLException: ERROR: column "evtjson" is of type json but expression is of type character varying

Hint: You will need to rewrite or cast the expression.

But, at least this tells me that the DB is recognizing the column as type JSON. 

OracleDocs shows a number of various methods to set the parameter value in the preparedStatement, but I'd rather not try them all if someone knows the answer. (http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html) These also reference an additional parameter, SQLType, but I can't find any refernce to these.
Should I try setAsciiStream? CharacterStream? CLOB? ???

I couldn't find any help or tutes on postgres or the web.

Thanks for any help.

-Curt

Re: Inserting JSON via Java PreparedStatment

От
"David G. Johnston"
Дата:

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

Which produce a different error:

Event JSON: {"New MbrID":29}

SQLException: ERROR: column "evtjson" is of type json but expression is of type character varying

Hint: You will need to rewrite or cast the expression.


​Take the hint, literally.  You never did show the SQL but usually the least complex way to solve this is to indeed transfer the data as a string/text and then instruction PostgreSQL to convert (i.e., cast) it to json.

SELECT (?)::json;  <-- that ? parameter is seen as text; then you convert it.  The parentheses should be optional but I use them to emphasize the point.

​then​

pStmt.setString(1, dtlRec.toString());​

David J.

Re: Inserting JSON via Java PreparedStatment

От
Adrian Klaver
Дата:
On 03/07/2016 05:25 AM, Curt Huffman wrote:
> Hello!
>
> I’m struggling to insert a JSON object into my postgres v9.4 DB. I have
> defined the column called "evtjson" as type json. (not jsonb)
> I am trying to use a prepared statement in Java (jdk1.8) to insert a
> Json object (built using JEE javax.json libraries) into the column, but
> I keep running into SQLException errors.
>
> I'm using JDBC 9.4.1208
>
> I create the JSON object using:
>
> |JsonObjectmbrLogRec =Json.createObjectBuilder().build();…mbrLogRec
> =Json.createObjectBuilder().add("New MbrID",newId).build();|
>
> Then I pass this object as a parameter to another method to write it to
> the DB using a prepared statement. (along with several other fields) As:
>
> |pStmt.setObject(11,dtlRec);|

You lost me here, I thought the object you are building is mbrLogRec?

>
> Using this method, I receive the following error:
>
>     at org.postgresql.util.PSQLException: No hstore extension installed.
>
>     at
>     org.postgresql.jdbc.PgPreparedStatement.setMap(PgPreparedStatement.java:553)
>
>
>     at
>     org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1036)
>
> I did try installing the hstore extension, but it then told me that it
> was not an hstore object.
>
> I have also tried:
>
> |pStmt.setString(11,dtlRec.toString());pStmt.setObject(11,dtlRec.toString());|
>
> Which produce a different error:
>
>     Event JSON: {"New MbrID":29}
>
>     SQLException: ERROR: column "evtjson" is of type json but expression
>     is of type character varying
>
>     Hint: You will need to rewrite or cast the expression.
>
> But, at least this tells me that the DB is recognizing the column as
> type JSON.
>
> OracleDocs shows a number of various methods to set the parameter value
> in the preparedStatement, but I'd rather not try them all if someone
> knows the answer.
> (http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html)
> These also reference an additional parameter, SQLType, but I can't find
> any refernce to these.
> Should I try setAsciiStream? CharacterStream? CLOB? ???
>
> I couldn't find any help or tutes on postgres or the web.
>
> Thanks for any help.
>
> -Curt
>


--
Adrian Klaver
adrian.klaver@aklaver.com


Re: Inserting JSON via Java PreparedStatment

От
rob stone
Дата:
On Mon, 2016-03-07 at 09:32 -0700, David G. Johnston wrote:
>
> > 
> > Hint: You will need to rewrite or cast the expression.
> >
> Take the hint, literally.  You never did show the SQL but usually the
> least complex way to solve this is to indeed transfer the data as a
> string/text and then instruction PostgreSQL to convert (i.e., cast)
> it to json.
>
> SELECT (?)::json;  <-- that ? parameter is seen as text; then you
> convert it.  The parentheses should be optional but I use them to
> emphasize the point.
>
> then
>
> pStmt.setString(1, dtlRec.toString());
>
> David J.
>

For some reason there is no java.sql.Type = JSON. There is ARRAY
though.

I would have written this:-

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

as

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

pStmt.setObject(11, mbrLogRec);

If you pass a string to your prepared statement and want to cast it in
your INSERT/UPDATE statement, you will probably have to include the
double quotes, colons and commas. Never tried it, just a guess.
Could become complicated when you have multiple pairs of JSON
attributes.

E.g.

JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID",
newId).add("Old MbrID","fred");


I'm sorry but I don't have time at the moment to knock up a test
program and verify any of this. I'm not an expert on JSON objects in
Java.

Just my two bob's worth.

HTH,
Rob



Re: Inserting JSON via Java PreparedStatment

От
"David G. Johnston"
Дата:
On Mon, Mar 7, 2016 at 8:15 PM, Curt Huffman <curt.huffman@gmail.com> wrote:
Thanks Rob & David!

I got it to work using the following:


String qry = "INSERT INTO event "
+ "(spotid, qid, userid, persid, ...., "
+ "evtvalue, evtdt, evtjson) "
+ "VALUES(?,?,?,?,?,?,?,?,?,?,to_json(?::json));";


​This is redundant (though possibly the to_json become a no-op in this case, idk).  Either cast (which is what you are doing when you say "?::json") so pass the text through the to_json function.  What you are saying here to "please convert this json value I am handing you to....json".

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

(another suggestion was to use: cast(? as json  which I haven't tried yet.)

​This has the benefit of being standard conforming, the "::" syntax is a PostgreSQL-ism.​


This worked with an ultra-simple, 1-pair json object. {"New MbrID":34}  I'll try it with more complex structures next.

Any opinions on using the postgres function, to_json, over the cast?

​I'm reasonably certain there is no actual difference between the two so whatever syntax seems more natural.​


However, from my (limited) understanding, I think I am now just incurring additional processing overhead from all of this.
I think that I am stuffing text into a JSON object, then converting it into a string for the preparedStatment, which then passes it to the JDBC driver to re-convert it into a JSON object, and gets ultimately stored as a text string in the column?  Is that correct?
I suspect I'll have to reverse the process to read it back out, yes?
 
Follow-up questions:
1) Since I'm not (yet) using JSONB, but just regular JSON column, is there much point to even using a JSON column?

​​Yes, you are using "text" as a serialization feature and by using a typed json column you are validating/constraining the text being sent to conform to JSON structure.  Unless you have solid and overwhelming proof that using JSON is unacceptably slow you should use it from a "proper model" perspective.
2) Will this method also work for JSONB column types?

​This is how you do type conversion in PostgreSQL, there is nothing here (aside from the unnecessary to_json function call) that is json/jsonb specific.

​David J.

Re: Inserting JSON via Java PreparedStatment

От
Curt Huffman
Дата:
Thanks Rob & David!

I got it to work using the following:


String qry = "INSERT INTO event "
+ "(spotid, qid, userid, persid, ...., "
+ "evtvalue, evtdt, evtjson) "
+ "VALUES(?,?,?,?,?,?,?,?,?,?,to_json(?::json));";

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

(another suggestion was to use: cast(? as json  which I haven't tried yet.)

This worked with an ultra-simple, 1-pair json object. {"New MbrID":34}  I'll try it with more complex structures next.

Any opinions on using the postgres function, to_json, over the cast?

However, from my (limited) understanding, I think I am now just incurring additional processing overhead from all of this.
I think that I am stuffing text into a JSON object, then converting it into a string for the preparedStatment, which then passes it to the JDBC driver to re-convert it into a JSON object, and gets ultimately stored as a text string in the column?  Is that correct?
I suspect I'll have to reverse the process to read it back out, yes?

Follow-up questions:
1) Since I'm not (yet) using JSONB, but just regular JSON column, is there much point to even using a JSON column?
2) Will this method also work for JSONB column types?

Finally, I humbly request a small addition to the postgres doco that illustrates this and the 'best' way to insert, manipulate, and retrieve JSON in postgres.  Maybe even a small tutorial?

Thanks again!
-Curt









On Tue, Mar 8, 2016 at 4:18 AM, rob stone <floriparob@gmail.com> wrote:
On Mon, 2016-03-07 at 09:32 -0700, David G. Johnston wrote:
>
> > 
> > Hint: You will need to rewrite or cast the expression.
> >
> Take the hint, literally.  You never did show the SQL but usually the
> least complex way to solve this is to indeed transfer the data as a
> string/text and then instruction PostgreSQL to convert (i.e., cast)
> it to json.
>
> SELECT (?)::json;  <-- that ? parameter is seen as text; then you
> convert it.  The parentheses should be optional but I use them to
> emphasize the point.
>
> then
>
> pStmt.setString(1, dtlRec.toString());
>
> David J.
>

For some reason there is no java.sql.Type = JSON. There is ARRAY
though.

I would have written this:-

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

as

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

pStmt.setObject(11, mbrLogRec);

If you pass a string to your prepared statement and want to cast it in
your INSERT/UPDATE statement, you will probably have to include the
double quotes, colons and commas. Never tried it, just a guess.
Could become complicated when you have multiple pairs of JSON
attributes.

E.g.

JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID",
newId).add("Old MbrID","fred");


I'm sorry but I don't have time at the moment to knock up a test
program and verify any of this. I'm not an expert on JSON objects in
Java.

Just my two bob's worth.

HTH,
Rob


Re: Inserting JSON via Java PreparedStatment

От
Adrian Klaver
Дата:
On 03/07/2016 07:15 PM, Curt Huffman wrote:
> Thanks Rob & David!
>
> I got it to work using the following:
>
>
> String qry = "INSERT INTO event "
> + "(spotid, qid, userid, persid, ...., "
> + "evtvalue, evtdt, evtjson) "
> + "VALUES(?,?,?,?,?,?,?,?,?,?,to_json(?::json));";
>
> and
> pStmt.setString (11,dtlRec.toString());
>
> (another suggestion was to use: cast(?asjson)   which I haven't tried yet.)
>
> This worked with an ultra-simple, 1-pair json object. {"New MbrID":34}
>   I'll try it with more complex structures next.
>
> Any opinions on using the postgres function, to_json, over the cast?
>
> However, from my (limited) understanding, I think I am now just
> incurring additional processing overhead from all of this.
> I think that I am stuffing text into a JSON object, then converting it
> into a string for the preparedStatment, which then passes it to the JDBC
> driver to re-convert it into a JSON object, and gets ultimately stored
> as a text string in the column?  Is that correct?
> I suspect I'll have to reverse the process to read it back out, yes?
>
> Follow-up questions:
> 1) Since I'm not (yet) using JSONB, but just regular JSON column, is
> there much point to even using a JSON column?
> 2) Will this method also work for JSONB column types?
>
> Finally, I humbly request a small addition to the postgres doco that
> illustrates this and the 'best' way to insert, manipulate, and retrieve
> JSON in postgres.  Maybe even a small tutorial?

The below?:

http://www.postgresql.org/docs/9.5/interactive/datatype-json.html#JSON-KEYS-ELEMENTS

http://www.postgresql.org/docs/9.5/interactive/functions-json.html


>
> Thanks again!
> -Curt
>


--
Adrian Klaver
adrian.klaver@aklaver.com