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

最新下载

热门教程

如何在Oracle存储过程中读取和写入BLOB?

时间:2026-08-19 09:54:48 编辑:袖梨 来源:一聚教程网

Oracle BLOB字段插入更新必须分三步:先用EMPTY_BLOB()占位,再SELECT...FOR UPDATE获取可写定位器,最后通过DBMS_LOB.WRITEAPPEND等过程写入字节;跳过任一环节将触发ORA-01461、ORA-22275等错误。

直接用 INSERT INTO t (blob_col) VALUES ('...')UPDATE t SET blob_col = :data 会失败——Oracle 不接受字符串字面量或变量直赋 BLOB,必须走 LOB 定位器路径。跳过 EMPTY_BLOB() 占位、FOR UPDATE 锁定、DBMS_LOB 写入三步中的任意一环,都会触发 ORA-01461ORA-22275 或静默截断。

写入 BLOB:必须分三步走,缺一不可

你不是在“插入值”,而是在“获取一个可写的 LOB 句柄并往里追加字节”。常见错误是试图一步到位,比如在 INSERT 中传 RAW 或 VARCHAR2 字符串。

  1. 第一步:占位 —— 用 INSERT INTO t (id, blob_col) VALUES (1, EMPTY_BLOB()),不能传任何实际二进制数据;否则报 ORA-01461: can bind a LONG value only for insert into a LONG column
  2. 第二步:锁定并获取句柄 —— 立即执行 SELECT blob_col INTO l_blob FROM t WHERE id = 1 FOR UPDATE;漏掉 FOR UPDATE 就报 ORA-22275: invalid LOB locator specified
  3. 第三步:写入 —— 对 l_blob 调用 DBMS_LOB.WRITEAPPEND(l_blob, LENGTH(v_raw), v_raw);每次最多写 32767 字节(VARCHAR2RAW 上限),超长必须循环分块

读取 BLOB:避免一次性加载,优先用分块拷贝

把整个 BLOB 赋给 PL/SQL 变量(如 l_blob BLOB)只是复制定位器,不搬数据;但若用 DBMS_LOB.SUBSTRUTL_RAW.CAST_TO_VARCHAR2 直接转字符串,极易触发 ORA-22835: buffer too small(因 VARCHAR2 最大 32767 字节,且 CLOB/BLOB 转换有隐式长度限制)。

  1. 安全读取大 BLOB 的推荐方式是 DBMS_LOB.COPY(dest_lob, src_lob, amount, dest_offset, src_offset),把指定段拷到另一个临时 LOB 或 OUT 参数中,客户端再分批拉取
  2. 若需提取原始字节做处理(比如校验、加密),用 DBMS_LOB.READ(src_lob, amount, offset, buffer),其中 buffer 类型必须是 RAW(32767);注意 offset 从 1 开始,不是 0
  3. 千万别用 UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(...)) 处理超过 4000 字节的内容——SUBSTR 返回 RAW,但 CAST_TO_VARCHAR2 会受 VARCHAR2 长度限制,且非 ASCII 字节可能乱码

临时 LOB:用完必须释放,否则内存泄漏

当你用 DBMS_LOB.CREATETEMPORARY(l_blob, TRUE) 创建可读写的临时 LOB(比如拼接多个 BLOB、解密后暂存),它不落盘,只在 PGA 中存在。这类 LOB 不受事务控制,也不自动清理。

  1. 必须显式调用 DBMS_LOB.FREETEMPORARY(l_blob),否则同一会话反复调用会吃光 PGA 内存
  2. cache => TRUE(第二个参数)表示启用缓存加速访问,对频繁读写的临时 LOB 是必要的;设为 FALSE 会导致性能骤降
  3. 临时 LOB 不能用于 INSERT ... SELECT 或跨过程传递——它只在当前 PL/SQL 单元生命周期内有效

批量更新 BLOB 字段:慎用 CAST 和 REPLACE

想在 BLOB 里做文本替换(比如改配置文件里的 URL)?别直接套 UTL_RAW.CAST_TO_VARCHAR2 + REPLACE + UTL_RAW.CAST_TO_RAW。BLOB 不是文本,编码、换行、二进制边界全不可控,且 CAST_TO_VARCHAR2 在 >4000 字节时必然报 ORA-22835

  1. 真正可行的路径是:先用 DBMS_LOB.CONVERTTOCLOB 把 BLOB 按指定字符集转成 CLOB(需确认原始内容确实是该编码的纯文本),再在 CLOB 上操作,最后用 DBMS_LOB.CONVERTTOBLOB 转回
  2. 如果只是简单字节替换(比如改 magic number),可用 UTL_RAW.REPLACE,但输入输出都必须是 RAW,且整块 BLOB 必须能载入 RAW 变量(≤32767 字节);超长需分段 READREPLACEWRITE
  3. 任何涉及 BLOB 全量转换的操作,在百万级记录上都会极慢;生产环境应尽量避免,改由应用层或外部工具处理

最易被忽略的一点:LOB 操作的事务语义和普通列不同。DBMS_LOB.WRITEAPPEND 修改的是 LOB 数据本身,但它的效果在 COMMIT 后才持久化;而 FOR UPDATE 锁定的是整行,不是 LOB 段——这意味着并发写入同一 LOB 时,仍可能因顺序错乱导致数据损坏,必要时得加应用层互斥。

热门栏目