You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:46:03