oracle 19c json列需用rs.getobject("col", string.class, sqltype.json)读取,驱动≥19.19、字符集al32utf8;23c需启用oracle.jdbc.jsonsupport=true并用jsonvalue.class;写入须合规json字符串且大json用setclob。

Oracle 19c JSON列必须用 rs.getObject("col", String.class, SQLType.JSON)
Java 17 连 Oracle 19c 时,原生 JSON 列不会自动转成字符串——rs.getString("col") 报错或返回乱码是常态。根本原因不是字符集或驱动太旧,而是 JDBC 驱动把 JSON 当作独立 SQL 类型处理,必须显式声明协议。
正确写法只有一种:
-
rs.getObject("col", String.class, SQLType.JSON)—— 第三个参数SQLType.JSON不可省略,否则 fallback 到默认行为,大概率失败 - 驱动必须是
ojdbc8≥ 19.19(即ojdbc8u3+),旧版压根不识别SQLType.JSON常量 - 服务端字符集必须为
AL32UTF8,否则中文显示为??? - 字段为 NULL 时,该调用返回
null,不是空字符串,需手动判空
Oracle 23c JSON列要用 oracle.jdbc.jsonSupport=true + JsonValue.class
23c 引入了真正的原生 JSON 映射能力,但默认关闭。不加配置时,rs.getObject("col", JsonValue.class) 直接抛 SQLFeatureNotSupportedException。
启用步骤分三步走:
- 用
ojdbc17.jar≥ 23.6(JDK 17 编译),ojdbc11.jar及更早版本完全无视该参数 - 连接 URL 或
Properties中添加:oracle.jdbc.jsonSupport=true - 读取时用:
rs.getObject("col", JsonValue.class),再通过getValueKind()判断类型,用asObject()/asArray()拆解
注意:JsonValue 是抽象类,实际返回的是内部实现(如 JsonString),不能强转 Jackson 的 JsonNode;想进 Jackson,得先调 toString() 拿格式化字符串。
写入 JSON 列不能用 setString(),必须合规生成
哪怕你传的是合法 JSON 字符串,用 PreparedStatement.setString(1, "{\"a\":1}") 插入到 JSON 列,Oracle 也会报 ORA-40442: JSON syntax error。
原因在于:Oracle 要求值必须通过 JSON 构造函数校验,JDBC 层不帮你加引号、不转义、不验证。
- 始终用 Jackson 的
objectMapper.writeValueAsString(obj)生成严格合规的 JSON 字符串 - 大 JSON(>4000 字节)必须用
setClob(1, new StringReader(jsonStr)),否则 ojdbc8 默认当VARCHAR2处理,触发截断或ORA-40495 - 插入前可加校验语句:
SELECT ? IS JSON FROM DUAL,绑定参数后查返回值是否为 1
Spring/JPA/MyBatis 默认不支持 JSON 列自动映射
无论 19c 还是 23c,JSON 列都不会被 Spring JDBC 的 BeanPropertyRowMapper、JPA 的默认实体映射、MyBatis 的 resultMap 自动识别。它们会跳过该列或报类型转换异常。
必须手动介入:
- Spring JDBC:写自定义
RowMapper,先rs.getObject("col", String.class, SQLType.JSON),再用 Jackson 解析为 POJO - MyBatis:注册
TypeHandler(如继承BaseTypeHandler<yourpojo></yourpojo>),并在resultMap中显式指定typeHandler="xxx.JSONTypeHandler" - JPA/Hibernate:需配
@Convert(converter = JsonStringConverter.class),converter 内部仍要走getObject(..., String.class, SQLType.JSON)
别指望 JSON_OBJECT 或 JSON_VALUE 的 SQL 表达式能绕过这个限制——只要结果列类型仍是 JSON,Java 端就必须按原规则读取。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











