2016-03-24 6 views
1

Das folgende ist mein Code, der eine Transaktion öffnet und eine Zeile in die Tabelle einfügt, während ich eine andere Verbindung öffne und die gleiche Tabelle abfrage. Das Programm legt bei Zeile (*) auf.Datenbank-Deadlock und TRANSACTION ISOLATION LEVEL

//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 ist ReadCommitted auf meiner Datenbank. Ich habe count=0 erwartet.

Es sieht so aus, als ob die Verbindung 1 die Tabelle sperrt, so dass die Verbindung 2 sie nicht lesen kann. Wenn das stimmt, warum gibt es TRANSACTION ISOLATION LEVEL?

Antwort

1

Sie haben eine erste Verbindung, die eine Transaktion öffnet, eine neue Zeile in eine Tabelle einfügt und nicht festschreibt. Es verfügt über eine beliebige Anzahl und Vielzahl von nicht gemeinsam nutzbaren Sperren für diese Tabelle.

Sie haben dann eine zweite Verbindung, die versucht, die Zählung zu lesen.

Ja, dies wird Deadlock (auf der App-Ebene, nicht auf der SQL-Ebene). Diese Verbindungen sind völlig unabhängig voneinander (es sei denn, Sie haben eine Umgebungs-TransactionScope, die Sie nicht erwähnt haben), so dass die zweite Verbindung wird blockiert werden. Es kann Ihnen die Zählung erst nach dem Festschreiben mitteilen, , weil es ReadCommitted ist - was bedeutet, dass es committednur lesen kann. Bis dahin: Es muss warten.

Wenn Sie explizit Vergangenheit die Sperre, verwenden Sie eine niedrigere Isolationsstufe wie READ UNCOMMITTED, oder fügen Sie einen expliziten Hinweis NOLOCK lesen möchten.

+0

Oh, ich https://msdn.microsoft.com/library/ms173763.aspx gefunden. Wird 'SET READ_COMMITTED_SNAPSHOT ON' den Deadlock lösen? – Gqqnbig

+0

@LoveRight das ist ... kein guter Weg, um einen Deadlock zu beheben. IMO gibt es 3 * gute * Möglichkeiten, dies zu beheben: 1) führen Sie die Zählung auf der gleichen Verbindung, wie die Transaktion verwendet wird (das wird Ihnen die neue Anzahl geben); 2) restrukturiere den Code so, dass du * dies nicht tust * - eine Transaktion offen zu lassen ist ein sehr schlechter Geruch - aber wenn du warten musst (um den zuverlässigen Wert zu erhalten) - dann * warte *; 3) Wenn Sie * hinter dem Schloss lesen müssen, verwenden Sie eine niedrigere Isolierung; Snapshot könnte dies lösen, aber aus Gründen, die im Grunde schreien "Ich verstehe nicht, was vor sich geht" - was nie gut ist –

+0

Ich mache nur Experimente. Vielen Dank – Gqqnbig

Verwandte Themen