以下是我的代码,它打开一个事务并向表中插入一行,同时我打开另一个连接并查询同一个表。该程序在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无法读取它。如果这是真的,为什么有交易隔离级别?
答案 0 :(得分:2)
您有第一个连接,用于打开事务,在表中插入新行,不提交。它在该表上有任意数量和种类的不可共享锁。
然后你有第二个尝试读取计数的连接。
是的,这将会死锁(在应用层,而不是在SQL层)。这些连接完全不相关(除非您有环境QVTKWidget
尚未提及),因此第二个连接将被阻止。它无法在提交之前告诉您计数,因为它是QWidget
- 这意味着它只能读取已提交的数据。在那之前:它需要等待。
如果您明确要阅读过去锁,请使用较低的隔离级别,例如TransactionScope
,或添加明确的ReadCommitted
提示。
答案 1 :(得分:0)
这是READ_COMMITED isolaction level的定义行为。
查看维基百科文章:https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_committed