如何使用Java preparedStatement将JSON对象插入Postgres?

May*_*ots 39 java postgresql json prepared-statement

我正在努力将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();
Run Code Online (Sandbox Code Playgroud)

然后我将此对象作为参数传递给另一个方法,以使用预准备语句将其写入DB.(以及其他几个领域)作为:

pStmt.setObject(11, dtlRec);
Run Code Online (Sandbox Code Playgroud)

使用此方法,我收到以下错误:

org.postgresql.util.PSQLException:未安装hstore扩展.at 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());
Run Code Online (Sandbox Code Playgroud)

哪会产生不同的错误:

事件JSON:{"New MbrID":29}

SQLException:错误:列"evtjson"的类型为json,但表达式的类型为字符变化

提示:您需要重写或转换表达式.

但是,至少这告诉我DB正在将列识别为JSON类型.我确实尝试安装hstore扩展,但它告诉我它不是一个hstore对象.

OracleDocs显示了许多用于在preparedStatement中设置参数值的方法,但如果有人知道答案,我宁愿不尝试所有方法.(http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html)这些还引用了一个额外的参数,SQLTYPE,但我不能找到这些任何引用.

我应该试试setAsciiStream吗?CharacterStream?CLOB?

wer*_*ero 46

这种行为非常烦人,因为在SQL命令中用作文字字符串时,JSON字符串被接受而没有问题.

在postgres驱动程序Github存储库中已存在一个问题(即使问题似乎是服务器端处理).

除了在sql字符串中使用强制转换(请参阅@a_horse_with_no_name的答案)之外,问题作者还提供了两个额外的解决方案:

  1. stringtype=unspecified在JDBC连接URL /选项中使用参数.

这告诉PostgreSQL所有text或varchar参数实际上都是未知类型,让它更自由地推断它们的类型.

  1. 将参数包装在org.postgresql.util.PGobject:

 PGobject jsonObject = new PGobject();
 jsonObject.setType("json");
 jsonObject.setValue(yourJsonString);
 pstmt.setObject(11, jsonObject);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!我认为选项2更符合我的要求.如果我正确理解代码,这更符合postgres打算使用JSON的方式.但是,这不包括从javax.json对象到字符串的另一个转换步骤,以将其包装在PG JSON对象中吗?(选项2,步骤3)看起来使用JSON对象通常是一种浪费,我现在最好坚持使用字符串操作.假设选项1会产生更广泛的性能影响,我是否正确,因为JDBC驱动程序必须进行大量的推断? (4认同)
  • @wero,你不是wero,你是英雄! (2认同)

小智 25

你可以像这样做,你只需要json字符串:

将查询更改为:

String query = "INSERT INTO table (json_field) VALUES (to_json(?::json))"
Run Code Online (Sandbox Code Playgroud)

并将参数设置为String.

pStmt.setString(1, json);
Run Code Online (Sandbox Code Playgroud)

  • 为什么需要`to_json()`部分?值(?:: json)工作正常 (2认同)

a_h*_*ame 13

将JSON作为String传递是正确的方法,但正如错误消息所示,您需要将语句中的参数INSERT强制转换为JSON值:

insert into the_table
   (.., evtjson, ..) 
values 
   (.., cast(? as json), ..)
Run Code Online (Sandbox Code Playgroud)

然后你可以pStmt.setString(11, dtlRec.toString())用来传递值


ped*_*iri 8

您有两种选择:

  1. 使用statement.setString(jsonStr),然后在sql语句中处理转换:

`

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

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);
Run Code Online (Sandbox Code Playgroud)

`我个人更喜欢后者,因为查询更简洁


Eli*_*jah 8

这里的大多数答案定义了以非标准方式使用 jdbc 插入 postgres json 字段的方法,即。它是特定于数据库实现的。如果您需要使用纯 jdbc 和纯 sql 将 java 字符串插入到 postgres json 字段中,请使用:

preparedStatement.setObject(1, "{}", java.sql.Types.OTHER)
Run Code Online (Sandbox Code Playgroud)

这将使 postgres jdbc 驱动程序(使用 org.postgresql:postgresql:42.2.19 测试)将 java 字符串转换为 json 类型。它还会将字符串验证为有效的 json 表示形式,而使用隐式字符串转换的各种答案则无法做到这一点 - 导致可能损坏持久的 json 数据。