不能把CLOB当字符串拼接或直接赋值,必须走DBMS_LOB初始化+分块写入路径,否则易报ORA-22285、ORA-22920或静默截断;INSERT需先EMPTY_CLOB()占位,再FOR UPDATE锁定,写入须分段(≤32767字节),临时CLOB须CREATETEMPORARY并FREETEMPORARY释放。

不能把 CLOB 当字符串拼接或直接赋值,必须走 DBMS_LOB 初始化 + 分块写入路径,否则大概率报 ORA-22285、ORA-22920 或静默截断。
INSERT 时必须先占位再 FOR UPDATE 锁定
直接 INSERT INTO t(clob_col) VALUES ('...') 超过 4000 字节会触发 ORA-01704;传空字符串或 NULL 则后续无法写入,报 ORA-22922 或 ORA-22275。
- 第一步:用
EMPTY_CLOB()占位,例如INSERT INTO my_table(id, content) VALUES (123, EMPTY_CLOB()) - 第二步:立刻执行
SELECT content INTO :clob_var FROM my_table WHERE id = 123 FOR UPDATE—— 缺FOR UPDATE就锁不住行,DBMS_LOB.WRITEAPPEND会失败 - 第三步:
:clob_var是 PL/SQL 中声明的CLOB类型变量,它现在指向一个可写的 LOB locator
写入超长内容必须分段,每次 ≤32767 字节
DBMS_LOB.WRITEAPPEND 的第三个参数是 VARCHAR2,而 PL/SQL 中 VARCHAR2 最大长度就是 32767 字节。试图传入更大的字符串会编译失败或运行时报 PLS-00172。
- 按 4000 或 8000 字节切片较稳妥,避开 UTF-8 多字节字符被截断的风险(如在“你好”的中间字节断开)
- 循环调用:
DBMS_LOB.WRITEAPPEND(clob_var, LENGTH(chunk), chunk),注意chunk必须是VARCHAR2,不能是CLOB - 若源数据本身是另一个 CLOB,优先用
DBMS_LOB.COPY,比逐段READ+WRITEAPPEND更快更安全
临时 CLOB 必须显式创建并释放
如果只是在存储过程中构造 CLOB(比如拼 XML、日志等),不存表,而是用作中间变量,那不能靠 EMPTY_CLOB(),得走临时 LOB 路径。
- 创建:
DBMS_LOB.CREATETEMPORARY(clob_var, TRUE),第二个参数TRUE启用缓存,性能更好 - 写入:一样用
DBMS_LOB.WRITEAPPEND,但无需FOR UPDATE - 释放:
DBMS_LOB.FREETEMPORARY(clob_var)必须写在过程末尾 —— 漏掉会导致 PGA 内存持续增长,长期运行后 OOM - 别对刚声明的
clob_var CLOB直接写,它只是空 locator,没初始化就调WRITEAPPEND会静默失败或报ORA-22285
CLOB offset/amount 单位易错:字符 vs 字节
读取时若用 DBMS_LOB.READ,CLOB 和 BLOB 的 offset 与 amount 含义完全不同,混用是乱码主因。
- CLOB:
offset从 1 开始,单位是**字符位置**;amount是要读的**字符数**(AL32UTF8 下,“你好”算 2 字符,占 6 字节) - BLOB:
offset和amount都是**字节位置和字节数**;若内容是 UTF-8 文本,得先用LENGTHB()查真实字节长度再传 - 常见错误:对 CLOB 用
LENGTH('中文')得到 2,再当字节数传给DBMS_LOB.READ的amount→ 只读 2 字节,卡在 UTF-8 中间,返回乱码或ORA-24801
最常被忽略的是:空 CLOB 不等于 NULL,也不等于可写对象;所有写操作前必须确认 locator 已有效初始化且处于可写状态 —— 这一步漏掉,后面全白忙。











