首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# IDataReader 資源洩漏根因與委派模式解決方案

     編輯:關於C#

問題背景

IDataReader 提供唯讀、前向的資料流存取,效能優於 DataSet(無需載入整個資料集到記憶體)。但在連線中斷、例外拋出、資料繫結失敗等情境下,若未正確關閉 SqlConnection,連線池會被佔用,導致後續請求無法取得連線(預設連線池上限約 100,Web 應用更低)。

錯誤範例


// 危險:若 DataBind 拋出例外,reader 與 connection 皆未關閉
using (var conn = new SqlConnection(connStr)) {
    var cmd = new SqlCommand(sql, conn);
    conn.Open();
    var reader = cmd.ExecuteReader();
    grid.DataSource = reader;
    grid.DataBind(); // 可能拋出例外
    reader.Close(); // 不會執行到
}

委派模式解決方案:控制反轉確保資源釋放

將「使用 Reader 的邏輯」封裝為委派,由資料存取元件負責建立、開啟、關閉連線與 Reader,確保 using 區塊涵蓋整個生命週期。


public static class DbHelper {
    public delegate void ReaderHandler(IDataReader reader);

    public static void ExecuteReader(string sql, ReaderHandler handler, params SqlParameter[] parameters) {
        using (var conn = new SqlConnection(connStr))
        using (var cmd = new SqlCommand(sql, conn)) {
            cmd.Parameters.AddRange(parameters);
            conn.Open();
            // CommandBehavior.CloseConnection:關閉 Reader 時自動關閉 Connection
            using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) {
                handler(reader); // 呼叫端處理資料繫結、讀取等邏輯
            }
        }
    }
}

// 使用端
DbHelper.ExecuteReader("SELECT * FROM Users WHERE Id=@id", reader => {
    grid.DataSource = reader;
    grid.DataBind();
}, new SqlParameter("@id", userId));

關鍵設計點

  • CommandBehavior.CloseConnection:Reader 關閉時自動關閉關聯連線,雙重保險
  • using 區塊巢狀:確保 SqlConnection、SqlCommand、SqlDataReader 皆正確 Dispose
  • 委派延遲執行:將資料處理邏輯外部化,資料層專注資源管理
  • 例外安全:任何例外皆會觸發 using 的 finally 區塊釋放資源

延伸:非同步版本


public static async Task ExecuteReaderAsync(string sql, Func handler, params SqlParameter[] parameters) {
    using (var conn = new SqlConnection(connStr))
    using (var cmd = new SqlCommand(sql, conn)) {
        cmd.Parameters.AddRange(parameters);
        await conn.OpenAsync();
        using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection)) {
            await handler(reader);
        }
    }
}

總結

委派模式將資源擁有權集中在資料存取層,徹底解決 IDataReader 洩漏問題,同時保持呼叫端彈性。現代開發建議搭配 Dapper、EF Core 等 ORM,進一步降低手寫 ADO.NET 程式碼風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved