应优先在SQL层用XMLQuery/XMLTable提取关键节点,避免Java端解析整棵XML;若必须Java处理,用XMLType.getStringVal().stringValue(conn)替代getString(),并注意驱动版本差异与内存风险。
OracleResultSet.getOPAQUE 返回 null 或 ClassCastException
直接调用 getopaque() 拿不到 xml 内容,是因为 oracle jdbc 驱动默认把 xmltype 映射成 oracle.sql.opaque,但这个对象本身不暴露 xml 字符串,且必须显式 cast 才能继续操作——很多代码直接 (opaque) rs.getobject("col") 会抛 classcastexception,因为实际返回的是 oracle.xdb.xmltype(驱动版本 ≥ 12.1 后默认启用新映射)。
- 确认驱动版本:用
ojdbc8.jar(12.2+)或ojdbc11.jar,旧版(如 ojdbc6)默认返回OPAQUE,新版默认返回XMLType - 别对
getOPAQUE()结果做裸 cast,先用rs.getObject("col") instanceof XMLType判断类型 - 如果必须兼容老驱动,改用
rs.getORAData("col", XMLType.class),而非getOPAQUE
XMLType.getString() 报 ORA-22950:无法对未排序的 XMLType 调用 getString()
这是最常卡住的点:XMLType.getString() 要求底层 XML 数据已“解析就绪”,而 Oracle 默认存储的 XMLType 可能是 binary 存储(STORE AS BINARY XML)且未触发解析,此时调用 getString() 就会崩出 ORA-22950。
- 优先用
xmlType.getStringVal().stringValue(conn)替代getString()(getStringVal()返回oracle.sql.CLOB,再转字符串更稳) - 若字段定义为
XMLType STORE AS CLOB,getString()通常可用;若是BINARY XML,必须走getStringVal()+stringValue() - 注意
stringValue(Connection)的参数不能传 null,必须传有效的Connection对象
用 getStringVal() 读大 XML 时内存暴涨或 OOM
getStringVal() 返回的是 CLOB,调用 stringValue() 会把整个 XML 加载进堆内存——哪怕 XML 有几 MB,也会瞬间吃光 JVM 堆。
- 小 XML(xmlType.getStringVal().stringValue(conn) 最简单
- 中大 XML(100KB–10MB):改用
xmlType.getCharacterStream(),配合BufferedReader流式读取,避免全量加载 - 超大 XML(>10MB):考虑在 SQL 层用
XMLQuery或XMLTable提前抽取关键节点,别把整棵 XML 拉到 Java 端
从 XMLType 提取特定节点内容(XPath 查询)
Java 端解析 XML 是下策,Oracle 自身支持 XPath 查询,应该尽量下推。但真要 Java 解析,别用 DocumentBuilder 直接 parse getString() 结果——它可能含非法字符或编码声明冲突。
- 先用
xmlType.getStringVal().getSubString(1, (int) xmlType.getStringVal().length())拿纯字符串,绕过 CLOB 编码歧义 - 解析前 strip 掉 XML 声明(如
<?xml version="1.0" encoding="UTF-8"?>),避免DocumentBuilder因编码声明和实际字节不一致报错 - 更稳的做法:SQL 里写
XMLQuery('/root/item/name' PASSING t.xml_col RETURNING CONTENT).getStringVal(),让 Oracle 做 XPath,Java 只收结果










