一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何将Oracle JSON字段映射为Java对象

时间:2026-08-08 11:09:55 编辑:袖梨 来源:一聚教程网

唯一安全的读取方式是 rs.getObject("col", String.class),因 Oracle 19c 原生 JSON 列需显式协议支持,该方法底层绑定 SQLType.JSON(ojdbc8u3+),返回 null 而非空字符串,其他方式均可能抛异常或乱码。

rs.getObject("col", String.class) 是唯一安全的读取方式

Oracle 19c 的原生 JSON 列在 JDBC 中不会自动转成字符串,rs.getString("col") 大概率抛出 SQLException: cannot convert to string 或返回乱码二进制(如 0x7B2261223A317D)。根本原因不是字符集问题,而是驱动把 JSON 当作独立 SQL 类型处理,必须显式声明协议。

正确做法只有一种:rs.getObject("col", String.class)。它底层依赖 SQLType.JSON 协议,但你不需要手动传入 SQLType.JSON 参数——ojdbc8u3+(即 19.19+)已将 String.class 绑定到该协议。传其他类型(如 JsonObject.class)会直接报 SQLFeatureNotSupportedException

  1. 驱动版本必须 ≥ ojdbc8u3(19.19),ojdbc7 等旧版连 JSON 类型都不识别,会报 ORA-00902: invalid datatype
  2. 字段为 NULL 时,rs.getObject("col", String.class) 返回 null,不是空字符串
  3. 别试 rs.getNString()rs.getClob()rs.getObject("col")(后者返回 oracle.sql.json.OracleJsonStructure,不能直接 toString()

用 Jackson 反序列化字符串为 Java 对象

拿到 String 后,交给 Jackson(推荐 ObjectMapper)做反序列化。这不是 JDBC 层的事,JDBC 只负责吐出合规 JSON 字符串。

关键点在于类结构要与 JSON 严格匹配:字段名、嵌套层级、集合类型都得一致;所有字段需有 public getter/setter(Jackson 默认靠反射调用);无参构造函数必须存在。

  1. 示例:若 JSON 是 {"name":"Alice","age":25},对应类必须有 getName()setName(String)getAge()setAge(int) 和无参构造函数
  2. 嵌套数组(如 "systems": [{"id":1,"name":"sys1"}])需定义 List 字段,并确保 SystemInfo 类也满足上述要求
  3. 避免用 Map 临时替代——它绕过编译检查,嵌套访问易错,且无法校验字段必填性

MyBatis/Spring JDBC 不会自动解析 JSON 列

MyBatis 的 BeanPropertyRowMapper 和 Spring JDBC 的默认映射机制,对 Oracle 原生 JSON 列完全无感知。它们只认标准 JDBC 类型(VARCHAR、NUMBER 等),遇到 JSON 列会 fallback 到通用类型处理,大概率失败或返回乱码。

必须手动干预:

  1. MyBatis:写自定义 TypeHandler,在 getResult(ResultSet rs, String column) 里调用 rs.getObject(column, String.class),再用 Jackson 解析
  2. Spring JDBC:用 ResultSetExtractorRowMapper,同样先取 String,再反序列化
  3. 别指望 @Column@Convert 注解自动生效——JPA 规范不定义 JSON 类型映射,Hibernate 需额外配置方言或自定义转换器

写入 JSON 字段:用 writeValueAsString + setClob

JSON 列写数据时,JDBC 不提供原生支持。你得自己保证输入是合法 JSON 字符串,再按常规方式写入。

  1. 小 JSON(确定 ≤ 4000 字节):用 ps.setString(idx, objectMapper.writeValueAsString(obj))
  2. 大 JSON:必须用 ps.setClob(idx, new SerialClob(objectMapper.writeValueAsString(obj).toCharArray())),否则可能触发 ORA-01461(bind variable type mismatch)
  3. 千万别直接 ps.setObject(idx, obj)——驱动不认识你的 POJO,会尝试转成 STRUCT,失败
  4. 服务端字符集必须是 AL32UTF8,JDBC URL 加 ?useUnicode=true&characterEncoding=UTF-8 防止中文乱码
真正卡住人的地方不在 Jackson,而在 JDBC 层那行看似简单的 rs.getObject("col", String.class):它依赖驱动版本、必须用 String.class、不能省略参数、NULL 返回值要单独判空——漏掉任一环,都会在运行时崩。

热门栏目