数据库死锁和事务隔离级别
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
以下是我打开一个事务并向 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