最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何在.NET中读写Oracle BLOB字段
时间:2026-08-15 10:10:49 编辑:袖梨 来源:一聚教程网
Oracle BLOB读取时Connection必须保持打开状态,因Oracle.ManagedDataAccess返回的是延迟加载的OracleBlob对象而非byte[],关闭连接后访问会抛InvalidOperationException;写入前须用EMPTY_BLOB()占位并SELECT FOR UPDATE获取可更新引用,全程需在同事务内完成。
Oracle BLOB读取时Connection必须保持打开状态
直接调用 OracleCommand.ExecuteScalar() 返回 byte[] 看似简洁,但 Oracle .NET 驱动(Oracle.ManagedDataAccess)对 BLOB 的默认行为是返回一个延迟加载的 OracleBlob 对象,而非实际字节数组。一旦 OracleConnection 关闭,再访问该对象的 Value 或尝试 CopyTo() 就会抛出 InvalidOperationException: "Connection is closed."。
实操建议:
- 读取前确认
OracleConnection.State == ConnectionState.Open - 用
OracleBlob.GetStream()获取流后,立即完成读取(如stream.ReadBytes()),不要跨连接生命周期缓存流或OracleBlob实例 - 若需异步读取,用
await blobStream.CopyToAsync(destStream),但同样要求连接在流读取期间保持打开 - 避免把
OracleBlob存入静态变量或长生命周期对象中
写入BLOB前必须先插入空LOB占位符
Oracle 不允许 INSERT 语句直接写入大二进制数据(尤其 > 32KB 时),否则会触发 ORA-01461: can bind a LONG value only for insert into a LONG column 错误。正确做法是分两步:先 INSERT 一条记录,其中 BLOB 字段用 EMPTY_BLOB() 占位;再用 SELECT FOR UPDATE 获取可更新的 OracleBlob 引用,最后写入数据。
实操建议:
- INSERT SQL 中写成
INSERT INTO table (id, name, content) VALUES (:id, :name, EMPTY_BLOB()) - 紧接着执行
SELECT content FROM table WHERE id = :id FOR UPDATE,并确保CommandBehavior.SequentialAccess不要启用(它会禁用更新能力) - 从
OracleDataReader获取OracleBlob后,调用blob.Write(byteArray, 0, byteArray.Length)或blob.SetStream(stream) - 整个过程必须在同一个
OracleTransaction内完成,否则 FOR UPDATE 会失效
大文件写入需控制缓冲区与超时设置
写入几十 MB 以上的 BLOB 时,默认的 CommandTimeout(30秒)和网络缓冲区容易导致超时或 OracleException: ORA-24345: A Truncation occurred。这不是数据截断,而是底层 TCP 包重组失败的误导性报错。
实操建议:
- 显式设置
OracleCommand.CommandTimeout = 300(单位秒),根据文件大小线性增加 - 避免一次性将整个文件读入内存——改用
FileStream+OracleBlob.SetStream()流式写入 - 连接字符串中添加
EnableExtendedMetaData=False可略微提升大 BLOB 性能(关闭元数据反射开销) - 若部署在 IIS,还需检查
web.config的maxRequestLength和executionTimeout,它们可能早于数据库层就中断上传
.NET Core/.NET 5+ 中 Oracle.ManagedDataAccess 版本兼容陷阱
Oracle 最新驱动对 .NET Core 支持存在版本断层:21.x 及以上版本仅支持 .NET 5+,而 19c 驱动(19.11)虽标称支持 .NET Core 3.1,但在 Linux 上读写 BLOB 时偶发 System.AccessViolationException(尤其使用 OracleBlob.Value)。
实操建议:
- 生产环境优先选用
Oracle.ManagedDataAccess 21.11(或最新稳定版),并确认目标运行时为 .NET 5 或更高 - 若必须用 .NET Core 3.1,请降级到
Oracle.ManagedDataAccess 19.10,且避免调用OracleBlob.Value,一律走GetStream()+ReadAsync() - Linux 下务必验证
libaio1是否已安装(apt-get install libaio1),缺失会导致 BLOB 操作静默失败
OracleBlob,得绕一层 IDataReader 才能拿到可更新引用。