数据库死锁和事务隔离级别

Database deadlock and TRANSACTION ISOLATION LEVEL

以下是我打开一个事务并向 table 插入一行的代码,同时我打开另一个连接并查询相同的 table。程序挂在第(*)行。

//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 锁定了 table,因此连接 2 无法读取它。如果那是真的,为什么会有 TRANSACTION ISOLATION LEVEL?

您有一个打开事务的第一个连接,将新行插入 table,并且 没有提交 。它在 table.

上有任意数量和种类的不可共享锁

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

是的,这会死锁(在app层,而不是在SQL层)。这些连接是完全不相关的(除非你有一个你没有提到的环境TransactionScope),所以第二个连接被阻止。在提交之前它无法告诉您计数, 因为它是 ReadCommitted - 这意味着它只能读取 committed 数据。在那之前:需要等待。

如果您明确想要读取 past 锁,请使用较低的隔离级别,例如 READ UNCOMMITTED,或添加明确的 NOLOCK 提示。

这是 READ_COMMITED 隔离级别的定义行为。

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