情景:
TransactionScope(TransactionScopeOption.Suppress)查询嵌入在包装器TransactionScope(TransactionScopeOption.Required)中。在“Suppress”查询之前,还有另一个与包装器“Required”TransactionScope相关联的查询。
这两个查询仅在一个表上重叠。先前的“必需”查询插入表中,后者“抑制”查询从表中选择。忽略这是多么愚蠢,以及“抑制”查询只会读取未锁定的行,因此不会包含新插入的结果。
行为:
我看到的行为是,如果表中有行,Insert将成功,然后Select将读取未锁定的行,然后继续。但是,如果表格为空,则“插入”将成功,但是“选择”将因“插入”而被卡住。
问题:
我想要获得的是在这种情况下如何跟踪锁定的概念性理解。我曾经认为表锁定是一种位切换,其中表被锁定或解锁,但它似乎更像是一个带有NOT EXISTS的CASE语句;在没有解锁行的情况下,表被锁定而不是表被解锁,但是其中的每一行当前都处于锁定状态。
我能找到的所有内容都表明确实存在不同级别的锁定(表格,行,页面等),但我找不到任何明确表示如果表格为空且在插入的数据上存在行锁,然后隐含表锁。最初我会期望Select只是简单地返回Null,但由于这不是我想的行为,我会联系专家,看看是否有人可以给我一个明确的理解。
注意:
RDBMS:SQL Server 2012
.NET Framework:4.0
核心行为:如果在Insert之前的表中存在记录,则两个查询都会成功,但如果表在Insert之前为空,则Select将被Insert阻止。
表:
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%'
答案 0 :(得分:1)
TransactionScope的默认IsolationLevel是“Serializable”。根据{{3}},在此隔离级别中,“可以读取但不修改易失性数据,并且在事务期间不能添加新数据”。 “可序列化”非常容易出现死锁。
SQLTransaction的默认IsolationLevel是ReadCommitted。尝试像这样声明你的交易范围
using (var scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.MaximumTimeout}))
它可以解决您的问题。
有关Msdn的更多信息:
最高隔离级别Serializable为中断事务提供了高度保护,但要求在允许任何其他事务对数据进行操作之前完成每个事务。