關於DbContext能不能單次請求內唯一?DbContex需不需要主動釋放?歡迎各路大俠來“參戰”!

来源:http://www.cnblogs.com/zhaopei/archive/2017/09/26/dispose-on-dbcontext.html
-Advertisement-
Play Games

基於上篇文章 "《HiBlogs》重寫筆記[1] 從DbContext到依賴註入再到自動註入" 園友 @Flaming丶淡藍@ 吳瑞祥 提出了討論和質疑,嚇得我連夜查詢資料(玩笑~)。 本來重點是想分析“自動註入”和對“註入”有更深的理解。不過既然有疑問和討論那也是很好的。總比時不時來篇“這個不行” ...


基於上篇文章《HiBlogs》重寫筆記[1]--從DbContext到依賴註入再到自動註入園友 @Flaming丶淡藍@ 吳瑞祥 提出了討論和質疑,嚇得我連夜查詢資料(玩笑~)。
本來重點是想分析“自動註入”和對“註入”有更深的理解。不過既然有疑問和討論那也是很好的。總比時不時來篇“這個不行”“那個要死了”的好。
之所以沒有在評論區馬上回覆,是因為我確實不懂。所以下班後趕緊查閱相關資料。
我個人得出來的結論是:DbContext可以單次請求內唯一,且可以不主動釋放。(其實當時心裡也納悶了。asp.net core就是這麼乾的啊,如果有問題還玩個毛線啊)
相關資料:http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext/
這篇資料博客應該還是有一定的權威性的,內容是EF團隊解釋回應。

Hello Jon,
The default behavior of DbContext is that the underlying connection is automatically opened any time is needed and closed when it is no longer needed. E.g. when you execute a query and iterate over query results using “foreach”, the call to IEnumerable<T>.GetEnumerator() will cause the connection to be opened, and when later there are no more results available, “foreach” will take care of calling Dispose on the enumerator, which will close the connection. In a similar way, a call to DbContext.SaveChanges() will open the connection before sending changes to the database and will close it before returning.
Given this default behavior, in many real-world cases it is harmless to leave the context without disposing it and just rely on garbage collection.
That said, there are two main reason our sample code tends to always use “using” or dispose the context in some other way:
1. The default automatic open/close behavior is relatively easy to override: you can assume control of when the connection is opened and closed by manually opening the connection. Once you start doing this in some part of your code, then forgetting to dipose the context becomes harmful, because you might be leaking open connections.
2. DbContext implements IDiposable following the recommended pattern, which includes exposing a virtual protected Dispose method that derived types can override if for example the need to aggregate other unmanaged resources into the lifetime of the context.
By the way, with DbContext the pattern to open the connection manually and override the automatic open/close behavior is a bit awkward:
((IObjectContextAdapter)dbContext).ObjectContext.Connection.Open()
But we have a bug to make this easier as it used to be with ObjectContext before, e.g.:
dbContext.Database.Connection.Open()
Hope this helps,
Diego

谷歌翻譯如下(英文不行,不知道翻譯是否正確):

喬恩,
DbContext的預設行為是底層連接在需要時自動打開,併在不再需要時關閉。例如,當您執行查詢並使用“foreach”迭代查詢結果時,對IEnumerable <T> .GetEnumerator()的調用將導致打開連接,並且稍後再沒有可用的結果,“foreach”將會關閉調用Dispose在枚舉器上,這將關閉連接。以類似的方式,調用DbContext.SaveChanges()將在將更改發送到資料庫之前打開連接,併在返回之前關閉它。
鑒於這種預設行為,在許多現實世界的情況下,離開上下文而不處理它,只依靠垃圾回收是無害的。
也就是說,我們的示例代碼往往總是使用“使用”或以其他方式處理上下文的兩個主要原因:
1.預設的自動打開/關閉行為相對容易被覆蓋:您可以通過手動打開連接來控制何時打開和關閉連接。一旦您在代碼的某些部分開始執行此操作,那麼忘記使用上下文會變得有害,因為您可能會泄露打開的連接。
2.DbContext根據推薦的模式實現IDiposable,其中包括暴露一個虛擬保護的Dispose方法,如果需要將其他非托管資源聚合到上下文的生命周期中,派生類型可以覆蓋。
順便說一下,用DbContext打開手動連接的模式,覆蓋自動打開/關閉的行為有點尷尬:
((IObjectContextAdapter)的DbContext).ObjectContext.Connection.Open()
但是,我們有一個錯誤,使之更容易,因為它曾經與ObjectContext之前,例如:
dbContext.Database.Connection.Open()
希望這可以幫助,
迭戈

光說不練假把式,我們還是親自來測試一下吧。

我們測試分兩種情況:

  • 1、主動釋放DbContext
  • 2、不釋放DbContext
  • 3、最好能用多線程模擬下併發
  • 4、然後查看執行時資料庫的連接數,和程式執行完之後資料庫的連接數。

測試代碼:

//模擬資料庫的一些操作(為了相對真實,包含了新增、修改和查詢)
private static void DbOperation(BloggingContext db)
{
    db.Blogs.Add(new Blog()
    {
        Rating = 1,
        Url = "www.i.haojima.net"
    });
    db.SaveChanges();

    db.Blogs.First().Url = "www.haojima.net";
    db.SaveChanges();

    foreach (var item in db.Blogs.Take(10).ToList())
    {
        Console.WriteLine("查詢到的博客id:" + item.BlogId);
    }
}

條件輸入:

static void Main(string[] args)
{
    Console.WriteLine("是否主動釋放DbContext(y/n)");
    var yes = Console.ReadLine();
    Console.WriteLine("請輸入模擬併發量");
    var number = Console.ReadLine();
    SemaphoreSlim _sem = new SemaphoreSlim(int.Parse(number));

迴圈代碼:

var i = 0;
while (i <= 5000)
{
    Console.WriteLine("啟動第" + i++ + "個線程");

    _sem.Wait();

    #region Thread
    new Thread(() =>
           {
               if (yes == "y")
               {
                   using (BloggingContext bloggingContext = new BloggingContext())//主動釋放
                   {
                       DbOperation(bloggingContext);
                   }
               }
               else
               {
                   BloggingContext bloggingContext = new BloggingContext();//不釋放
                   DbOperation(bloggingContext);
               }

           }).Start();
    #endregion

    _sem.Release();

查看連接數量(sql語句):

SELECT count(1) AS '連接到EFCoreDemoDB2資料庫的數量' FROM
[Master].[dbo].[SYSPROCESSES] WHERE [DBID] IN ( SELECT 
   [DBID]
FROM 
   [Master].[dbo].[SYSDATABASES]
WHERE 
   NAME='EFCoreDemoDB2'
)

操作截圖如下(你也可以下載demo代碼自行測試):

主動釋放、模擬200併發量

資料庫看到的連接數最多的時候54個

不釋放、模擬200併發量

資料庫看到的連接數最多的時候56個

程式執行完成後,連接自動釋放了

 

【技巧】:
我們使用ef或dbcontext的時候主要註意三個問題:

  • 1、多個線程不能訪問同一個dbcontext
  • 2、同一個跟蹤實體不能被多個dbcontext操作
  • 3、如果查詢數據不需要被修改,一定按需查詢.select(t=>new Dto(){ })。最不濟也要AsNoTracking().ToList()。
    一般也就不會出現奇怪的問題了。

 

【註意】運行測試的時候用命令行執行或者“開始執行不調試”

demo:https://github.com/zhaopeiym/BlogDemoCode/tree/master/EFCoreDemo

當然,我也不知道這種測試是否合理。如果園友有更好的測試方式可以提供。歡迎大家交流。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 參考:https://github.com/NLog/NLog/wiki/Tutorial 步驟: 1. 使用Nuget安裝NLog.Extensions.Logging 2.編寫代碼(到這步運行代碼,不報錯,但是也不會有log輸出,因為沒有設置配置文件) 3. 編寫配置文件 在項目下新增加NLog ...
  • namespace params可變參數{ class Program { static void Main(string[] args) { int[] num = {66,99,55,44, }; Test("老王",num); Test("老王",55,55,55); //從方法哪裡的參數可以 ...
  • ASP.NET MVC4,ASP.NET MVC5中對JS和CSS的引用又做了一次變化,在MVC3中我們這樣引用資源文件: 將在運行的時候自動將虛擬(相對)路徑轉換為應用程式絕對路徑。這是比較傳統的引用方式,儘管他做了一次轉換操作,對伺服器的請求數量壓力並沒有什麼改進的變化,所以推測可能出於模塊化設 ...
  • 1、刪除 xxxAreaRegistration.cs文件 2、HomeController 2、JoinController 3、生成鏈接 @Url.RouteUrl("JoinCode", new {action="Index",controller="Join",code=item["code ...
  • 具名參數 和 可選參數 是 C# framework 4.0 出來的新特性。 一. 常規方法定義及調用 調用時,參數順序(類型)必須與聲明一致,且不可省略。 二. 可選參數的聲明及調用 可選參數分為兩種情況: 1. 部分參數可選; 2. 全部參數都是可選 註: 當參數為部分可選時, 可選參數 的聲明 ...
  • public class SqlHlper { public static readonly string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString; //執行增刪改 public stati ...
  • namespace ArrayListd的長度問題{ class Program { static void Main(string[] args) { //需要的參數是object類型 //alt+shift+F10添加引用using System.Collections; ArrayList l ...
  • 1.複習里氏轉換:1)、子類可以賦值給父類(如果有一個方法需要一個父類作為參數,我們可以傳第一個子類對象)2)、如果父類中裝的是子類對象,則可以將這個父類強轉為子類對象 is和as判斷轉換成功失敗 1 Person p = new Student(); 2 //if(p is Student) 3 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...