核心是流式读写:必须用getCharacterStream()分块读取,禁用getString()和getSubString()以防OOM;写入优先用setCharacterStream()或createClob()+setClob(),批量操作需关闭自动提交并配置驱动参数。

Java 中用 JDBC 处理 Oracle 数据库的 CLOB 字段,核心是避免一次性加载全部内容进内存,必须走流式读写。直接调用 getString() 或 getSubString() 容易触发 OutOfMemoryError,尤其当 CLOB 超过几 MB 时就非常危险。
读取 CLOB:必须用 getCharacterStream() 分块读
不要用 rs.getString("col") —— 它可能截断(如 ojdbc 默认只读前 4000 字节),也可能返回 null 即使字段非空。
- 先调用
rs.getClob("col"),检查返回值是否为null(对应 SQL NULL) - 再调用
clob.getCharacterStream()获取Reader,不是InputStream - 用固定大小字符数组(如
char[8192])循环读取,禁用readLine()和lines()(不支持 mark/reset,且会吃掉换行) - 读完建议显式调用
clob.free()(JDBC 4.0+),防止连接池中 LOB 句柄泄漏
写入 CLOB:优先用 setCharacterStream() 直传流
别用 ps.setString(1, hugeText) —— 超长会报 ORA-01461(试图把大字符串当 VARCHAR2 绑定)。
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 推荐方式:
ps.setCharacterStream(1, reader, length),让驱动内部处理 CLOB 创建和写入 - 若需复用 Clob 对象,可用
conn.createClob()→clob.setString(1, text)→ps.setClob(1, clob),但要确保写入后流已关闭、连接未提前释放 - Oracle 12.1+ 驱动可启用
SetBigStringTryClob=true参数,使setString()自动降级为 CLOB 写入(需驱动 ≥ 12.1.0.2)
批量操作与连接池注意事项
批量插入含 CLOB 的记录,默认行为极低效:每条都单独分配 LOB 定位符,网络往返多、日志膨胀快。
立即学习“Java免费学习笔记(深入)”;
- 必须关闭自动提交:
conn.setAutoCommit(false),batch 执行后再统一commit() - HikariCP 等连接池下,
setCharacterStream()传入的Reader必须保持打开状态,直到executeUpdate()完成 - 生产环境建议用 ojdbc8(≥19.3),并加连接参数:
oracle.jdbc.defaultLobPrefetchSize=0,禁用预取,强制流式
转 String 要谨慎:不是所有 CLOB 都适合全量加载
clob.toString() 返回的是对象哈希,不是内容;clob.length() 在某些驱动里本身就会触发全量加载,且长度超 Integer.MAX_VALUE(约 2GB)会直接抛异常。
- 确定内容较小时(如 IOUtils.toString(clob.getCharacterStream(), StandardCharsets.UTF_8)
- 不确定大小时,必须分块读 + 长度计数防死循环,例如:
long total = 0; while ((n = reader.read(buf)) != -1 && total

















