数据库死锁和TRANSACTION ISOLATION LEVEL

时间:2016-03-24 22:53:55

标签: c# sql-server transactions deadlock

以下是我的代码,它打开一个事务并向表中插入一行,同时我打开另一个连接并查询同一个表。该程序在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();
}

我的数据库中的交易隔离级别为ReadCommitted。我期待count=0

看起来连接1会锁定表,因此连接2无法读取它。如果这是真的,为什么有交易隔离级别?

2 个答案:

答案 0 :(得分:2)

您有第一个连接,用于打开事务,在表中插入新行,不提交。它在该表上有任意数量和种类的不可共享锁。

然后你有第二个尝试读取计数的连接。

是的,这将会死锁(在应用层,而不是在SQL层)。这些连接完全不相关(除非您有环境QVTKWidget尚未提及),因此第二个连接被阻止。它无法在提交之前告诉您计数,因为它是QWidget - 这意味着它只能读取已提交的数据。在那之前:它需要等待。

如果您明确要阅读过去锁,请使用较低的隔离级别,例如TransactionScope,或添加明确的ReadCommitted提示。

答案 1 :(得分:0)

这是READ_COMMITED isolaction level的定义行为。

查看维基百科文章:https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_committed