从Oracle数据库提取PDF Blob并加密后更新回原Blob列的实现疑问
解决Oracle Blob PDF提取、加密并更新回数据库的问题
现有代码存在的问题
- SQL无筛选逻辑:原查询未根据传入的
id_file定位目标记录,会读取全表数据,且未使用参数化查询存在注入风险 - 流位置错误:将Blob写入MemoryStream后,流指针停在末尾,直接用
PdfReader.Open会读取空内容 - 资源泄漏:数据库连接、命令、阅读器等资源未通过
using自动释放,易导致连接池耗尽 - 加密后流处理失效:加密PDF写入原流时未重置状态,且关闭流后返回,调用方无法使用已关闭的流
- 缺失数据库更新逻辑:仅完成提取和加密,未将加密后的内容写回原Blob列
修正后的完整实现代码
public void EncryptPdfAndUpdateDb(int idFile) { string connStr = "User Id=user; Password=pass; Data Source=oracle; Pooling=false"; // using自动管理数据库连接,确保释放 using (OracleConnection con = new OracleConnection(connStr)) { con.Open(); // 1. 提取指定ID的Blob数据 string selectSql = "SELECT blob_column FROM your_table WHERE id_file = :IdFile"; using (OracleCommand selectCmd = new OracleCommand(selectSql, con)) { selectCmd.Parameters.Add(":IdFile", OracleDbType.Int32).Value = idFile; selectCmd.InitialLOBFetchSize = -1; // 一次性读取完整Blob,避免分段加载 using (OracleDataReader dr = selectCmd.ExecuteReader()) { if (!dr.Read()) { throw new InvalidOperationException($"未找到ID为{idFile}的记录"); } using (OracleBlob oracleBlob = dr.GetOracleBlob(0)) { using (MemoryStream originalMs = new MemoryStream()) { oracleBlob.CopyTo(originalMs); originalMs.Position = 0; // 重置流指针到开头,确保PdfReader能读取内容 // 2. 加密PDF using (PdfDocument document = PdfReader.Open(originalMs, PdfDocumentOpenMode.Modify)) { PdfSecuritySettings securitySettings = document.SecuritySettings; securitySettings.UserPassword = "user"; securitySettings.OwnerPassword = "12345"; securitySettings.PermitAccessibilityExtractContent = false; securitySettings.PermitAnnotations = false; securitySettings.PermitAssembleDocument = false; securitySettings.PermitExtractContent = false; securitySettings.PermitFormsFill = true; securitySettings.PermitFullQualityPrint = false; securitySettings.PermitModifyDocument = true; securitySettings.PermitPrint = false; // 将加密后的PDF写入新流 using (MemoryStream encryptedMs = new MemoryStream()) { document.Save(encryptedMs); encryptedMs.Position = 0; // 重置指针,准备写入数据库 // 3. 更新加密后的Blob回数据库 string updateSql = "UPDATE your_table SET blob_column = :EncryptedBlob WHERE id_file = :IdFile"; using (OracleCommand updateCmd = new OracleCommand(updateSql, con)) { updateCmd.Parameters.Add(":EncryptedBlob", OracleDbType.Blob).Value = encryptedMs; updateCmd.Parameters.Add(":IdFile", OracleDbType.Int32).Value = idFile; int affectedRows = updateCmd.ExecuteNonQuery(); if (affectedRows == 0) { throw new InvalidOperationException($"更新ID为{idFile}的记录失败,未找到匹配行"); } } } } } } } } } }
关键优化点说明
- 参数化查询:所有SQL操作使用参数绑定,避免注入风险,同时精准定位目标记录
- 资源自动释放:所有实现
IDisposable的对象(连接、命令、阅读器、Blob、流)都用using包裹,自动回收资源 - 流指针重置:每次读写流后重置
Position为0,确保后续操作能正确读取流内容 - 完整Blob读取:设置
InitialLOBFetchSize = -1,一次性获取完整Blob数据,避免分段读取的复杂处理 - 异常提示:添加记录不存在、更新失败的针对性异常,方便排查问题
内容的提问来源于stack exchange,提问作者Helicobacter
相关产品推荐
相关产品推荐

