Oracle更新LOB字段必须先用EMPTY_CLOB()/EMPTY_BLOB()占位并FOR UPDATE锁定,再分段调用DBMS_LOB.WRITEAPPEND(每次≤32767字节),临时LOB需cache=>TRUE且最后调用FREETEMPORARY释放。

直接用 UPDATE table SET lob_col = ? 更新大对象字段,在绝大多数数据库里都会失败或静默截断——LOB 不是普通字段,不能当字符串或字节数组直接赋值。
Oracle:必须走 EMPTY_CLOB()/EMPTY_BLOB() + FOR UPDATE + DBMS_LOB 路径
ORA-22275 或 ORA-01461 错误说明你跳过了 LOB 定位器初始化步骤。Oracle 强制要求先占位、再获取有效 locator、最后写入。
- INSERT 或 UPDATE 时,
lob_col必须设为EMPTY_CLOB()或EMPTY_BLOB(),不能传字符串字面量 - 后续操作前,必须
SELECT lob_col INTO :loc FROM table WHERE ... FOR UPDATE—— 缺少FOR UPDATE会报 ORA-22275 - 写入超长内容(>32767 字节)必须分段调用
DBMS_LOB.WRITEAPPEND,每次传VARCHAR2或RAW,长度 ≤32767 - 用
DBMS_LOB.LOADCLOBFROMFILE加载文件时,src_csid参数必须匹配文件编码(如NLS_CHARSET_ID('AL32UTF8')),否则乱码
SQL Server:varbinary(max) 可直赋,但大值更新有隐式限制
varbinary(max) 和 varchar(max) 表面上支持直接 UPDATE,但实际受客户端协议和内存约束影响极大。
- 应用层传入的
varbinary(max)值若超过max_packet_size(默认 4MB),会在网络层被截断,无明确错误提示 - 存储过程中拼接多个
+操作(如@a + @b + @c)可能触发隐式转换,导致中间结果被截为 8000 字节 - 真正安全的大对象更新,应使用
WRITE方法做分块覆盖:UPDATE t SET blob_col.WRITE(@chunk, @offset, LEN(@chunk)) WHERE id = @id - 不推荐在 T-SQL 中模拟流式读取;CLR 函数(如
SqlBytes.Stream)只适用于 .NET 集成场景,且 Oracle/MySQL 完全不兼容
PostgreSQL:lo_import/lo_from_bytea 返回 OID,不是数据本身
PostgreSQL 的大对象(LO)是独立于表的存储实体,OID 是指针,不是值。直接把 bytea 当 LO 用会出错。
-
lo_import('/path')只接受数据库服务器本地路径,且必须在BEGIN...COMMIT块内调用,否则报large object functions cannot be used outside a transaction block - 客户端上传需用
lo_from_bytea(0, $1),返回 OID 后存入业务表的oid类型字段;别用int4接收返回值 -
lo_export(oid, '/path')只能写服务器磁盘,无法直出到客户端;想传回应用层,得用lo_get(oid)—— 但它会一次性加载全部内容进内存,>100MB 小心 OOM - 纯 SQL 无法流式读取 LO;分块读必须用 libpq 的
lo_open/lo_read,或在 PL/pgSQL 中调用 C 函数
最易被忽略的一点:所有数据库的 LO 写入都不是原子性的“值替换”,而是“定位器操作”。一旦漏掉 FOR UPDATE、事务包裹、显式关闭句柄(如 DBMS_LOB.FILECLOSE)或 FREETEMPORARY,轻则数据损坏,重则 PGA/内存泄漏,且问题往往延迟暴露。

















