2016-03-24 44 views
1

以下是我的代碼,它打開一個事務並在表中插入一行,同時打開另一個連接並查詢同一個表。程序在Line(*)掛起。數據庫死鎖和事務隔離級別

//TestTable is empty. 
using (connection1 == new SqlConnection(OpConsoleLib.std.CONNECTIONSTRING)) { 
    connection1.Open(); 
    SqlCommand cmd = new SqlCommand("Insert into TestTable values('hello')", connection1); 
    cmd.Transaction = connection1.BeginTransaction(); 
    cmd.ExecuteNonQuery() 

    using (SqlConnection connection2 = new SqlConnection(OpConsoleLib.std.CONNECTIONSTRING)) { 
     connection2.Open(); 
     SqlCommand cmd2 = new SqlCommand("Select count(*) from TestTable where name='hello'", connection2); //(*) 

     int count=Convert.ToInt32(cmd2.ExecuteScalar()); 

    } 

    cmd.Transaction.Commit(); 
} 

TRANSACTION ISOLATION LEVEL is ReadCommitted on my database。我期待count=0

它看起來像連接1鎖定表,因此連接2無法讀取它。如果那是真的,爲什麼有交易隔離級別?

回答

1

您有第一個連接打開一個事務,向表中插入一個新行,並且沒有提交。它在該表上具有任何數量和種類的不可共享的鎖。

然後您有第二個連接嘗試讀取計數。

是的,這會死鎖(在應用層,而不是在SQL層)。這些連接是完全無關的(除非你有一個環境TransactionScope,你沒有提到),所以第二個連接被阻止。它不能告訴你的計數,直到提交,,因爲它是ReadCommitted - 這意味着它只能讀取提交的數據。在此之前:它需要等待。

如果你明確要讀過去鎖定,用較低的隔離級別,如READ UNCOMMITTED,或增加一個顯NOLOCK提示。

+0

哦,我發現https://msdn.microsoft.com/library/ms173763.aspx。 SET READ_COMMITTED_SNAPSHOT是否解決死鎖問題? – Gqqnbig

+0

@LoveRight這是...不是解決僵局的好方法。國際海事組織有3 *好*的方法來解決這個問題:1)執行與交易相同的連接計數(這會給你新的計數); 2)重組代碼,以便你*不這樣做* - 在這裏打開一個事務是一個非常難聞的氣味 - 但如果你需要等待(獲得可靠的值) - 然後*等*; 3)如果你*必須*讀過鎖,使用較低的隔離度;快照可能會解決這個問題,但基於這樣的原因,基本上尖叫着「我不明白髮生了什麼」 - 這是從來沒有好過的。 –

+0

我只是在做實驗。謝謝 – Gqqnbig