2

场景:
嵌入在包装器 TransactionScope(TransactionScopeOption.Required) 中的 TransactionScope(TransactionScopeOption.Suppress) 查询。在“抑制”查询之前,还有另一个与包装“必需”TransactionScope 关联的查询。

这两个查询只在一张表上重叠。前面的“必需”查询插入到表中,后面的“抑制”查询从表中选择。忽略这是多么愚蠢,“抑制”查询只会读取未锁定的行,因此不会包括新插入的结果。

行为:
我看到的行为是,如果表中有行,则插入将成功,然后选择将读取未锁定的行,然后继续。但是,如果表为空,则 Insert 会成功,但 Select 会因为被 Insert 阻塞而卡住。

问题:
我想要获得的是对在这种情况下如何跟踪锁定的概念性理解。我曾经认为表锁定是一种位切换,其中表被锁定或解锁,但它似乎更像是一个带有 NOT EXISTS 的 CASE 语句;在没有解锁行的情况下,表被锁定而不是表被解锁,但其中的每一行当前都处于锁定状态。

我能够找到的所有内容都表明确实存在不同级别的锁定(表、行、页面等),但我找不到任何明确说明表为空且存在行锁的内容在插入数据时,隐含表锁。最初我预计 Select 会简单地返回 Null,但由于这不是我认为我会联系专家的行为,看看是否有人可以给我一个明确的理解。

注意:
RDBMS:SQL Server 2012
.NET Framework:4.0
核心行为:如果在插入之前表中存在记录,则两个查询都会成功,但如果在插入之前表为空,则选择会被插入阻止。

桌子:

Create Table Random(ID Int Identity, Word Varchar(50), TimeInserted DateTime)

插入查询:

Insert Random(Word, TimeInserted)
Select 'Word', GetDate()

选择查询:

Select Max(TimeInserted)
From Random
Where Word Like 'A%'
4

1 回答 1

1

TransactionScope 的默认 IsolationLevel 是“Serializable”。根据Msdn的说法,在这个隔离级别中“易失性数据可以读取但不能修改,事务期间不能添加新数据”。“可序列化”非常容易出现死锁。

SQLTransaction 的默认 IsolationLevel 是 ReadCommitted。尝试像这样声明您的事务范围

using (var scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.MaximumTimeout}))

它可能会解决您的问题。

有关MSDN的更多信息:

最高的隔离级别 Serializable 提供了对中断事务的高度保护,但要求每个事务在允许任何其他事务对数据进行操作之前完成

于 2013-02-20T19:53:28.977 回答