Monday, October 19, 2009 - 文章

觀察LINQ to SQL DataContext的連線開啟時機

昨天的文章發表後,有兩位網友提到了DataContext是否要加using的議題。

我接觸LINQ to SQL是由Scott Gu的這幾篇文章開始入門的,在他的範例中沒有特別提到using,我也自始就忽略DataContext有實做IDispose這件事。雖然用using包住絕對有益無害(只要小心using中間過程如將DataContext傳到外部,要留意using結束後外部就不可再繼續叫用),但我倒認為DataContext裡的Connection應該不是一new DataContext就建立一條連線不放,直到Dispose()才結束釋出,而是Query時開啟連線,用完即關閉;Update時再重新開啟連線,用完再度關閉。如此【最後一刻開啟、用完立即關閉】的寫法,較符合珍貴資源應用的Best Practice;換句話說,在DataContext裡應該就己實踐了類似using (SqlConnection)的做法,盡可能讓連線時間最短化。不過,畢竟只是猜想,不如做個實驗觀察一下。

static void log(string msg)
{
    Console.WriteLine("{0:HH:mm:ss.fff} {1}", DateTime.Now, msg);
    System.Threading.Thread.Sleep(2000);
}
 
static void Main(string[] args)
{
    MyLabDataContext db = new MyLabDataContext();
    log("DataContext created");
    var q = from o in db.Players
            select o;
    log("LINQ defined");
    Console.WriteLine(q.Count());
    log("Get the row count");
    Player p = new Player()
    {
        UserName = "Darkthread",
        RegDate = new DateTime(2009, 1, 1),
        HiScore = 65536
    };
    db.Players.InsertOnSubmit(p);
    log("InsertOnSubmit");
    db.SubmitChanges();
    log("SubmitChanges");
    db.Dispose();
    log("Disposed");
    Console.Read();
}

在以上的程式範例中,每個動作間相隔兩秒鐘,並記錄發生時間,以便跟SQL Profiler記錄的時間對照。依我的推論,連線開啟關閉應該會發生在q.Count()與db.SubmitChanes()。

00:55:50.285 DataContext created
00:55:52.292 LINQ defined
0
00:55:54.730 Get the row count
00:55:56.736 InsertOnSubmit
00:55:58.850 SubmitChanges
00:56:00.850 Disposed

接著我們對照一下SQL Profiler看到的結果:

 

 

EventClass StartTime EndTime TextData
Audit Login 2009-10-19 00:55:54.587 NULL -- network protocol: TCP/IP
Audit Logout 2009-10-19 00:55:54.587 2009-10-19 00:55:54.647 NULL
RPC:Completed 2009-10-19 00:55:54.647 2009-10-19 00:55:54.647 exec sp_reset_connection
Audit Login 2009-10-19 00:55:54.647 NULL -- network protocol: TCP/IP
SQL:BatchCompleted 2009-10-19 00:55:54.647 2009-10-19 00:55:54.647 SELECT COUNT(*) AS [value] FROM [dbo].[Player] AS [t0]
Audit Logout 2009-10-19 00:55:54.647 2009-10-19 00:55:58.720 NULL
RPC:Completed 2009-10-19 00:55:58.720 2009-10-19 00:55:58.720 exec sp_reset_connection
Audit Login 2009-10-19 00:55:58.720 NULL -- network protocol: TCP/IP
RPC:Completed 2009-10-19 00:55:58.810 2009-10-19 00:55:58.810 exec sp_executesql N'INSERT INTO [dbo].[Player]([UserName], [RegDate], [HiScore]) VALUES (@p0, @p1, @p2)',N'@p0 nvarchar(10),@p1 datetime,@p2 int',@p0=N'Darkthread',@p1='2009-01-01 00:00:00',@p2=65536
Audit Logout 2009-10-19 00:55:58.720 2009-10-19 00:59:25.550 NULL

我這麼解讀,00:55:50建立DataContext時並沒有開啟任何連線,q.Count()發生於00:55:54,此時有了第一次Audit Login。基於Connection Pooling的特性,每次SqlConnection.Open()時,會產生一個Audit Logout、exec sp_reset_connection再加一個Audit Login,而在此發生了兩次,第一次在00:55:54,第二次在00:55:58,剛好就是q.Count()及SubmitChanges()發生的時點。

最後一個Audit Logout則是出現在程式完全結束,Process終止,Connection Pool的連線真的被關閉時(00:59:25)。

由以上觀察,應可印證我的推論"LINQ to SQL裡DataContext內部對SqlConnection的處理原則為: 必要時才開啟,用後立即關閉"。進一步延伸,加上using應不會產生顯著影響,但對於實作IDispose的物件使用using絕對是良好的習慣。

搜尋

Go

<October 2009>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication