【问题标题】:Does the first insert into a table effectively lock the entire table?第一次插入表是否有效地锁定了整个表?
【发布时间】:2013-02-20 19:28:58
【问题描述】:

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

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

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

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

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

注意事项:
关系型数据库:SQL Server 2012
.NET 框架: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%'

【问题讨论】:

  • 您是否对选择使用可序列化隔离?还有什么是表结构和查询?
  • 是可序列化的,表结构和查询应该无关紧要。 “必需”查询是一个 INSERT,它排除了作为 SELECT 的“抑制”查询。将表视为三列,一个 IDENTITY 列,一个 Varchar(50) 和一个 DateTime 列。插入添加 Varchar(50) 和 DateTime(身份自动增量),并且选择正在读取 DateTime。
  • 查询和表结构确实很重要,因为这决定了它是锁定整个对象还是锁定键范围,以及如果是后者,则锁定哪个特定范围。
  • 好吧,问题已更新。感谢您的帮助。
  • 无论表是否为空,这些查询都应始终阻塞,除非读取未提交或快照隔离(或者如果您使用with (readpast) 提示)。插入将使用MAX(TimeInserted) 添加一行,而SELECT 查询在插入提交之前无法读取它。

标签: .net sql sql-server locking transactionscope


【解决方案1】:

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

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

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

它可能会解决你的问题。

更多关于MSDN

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

【讨论】:

  • 感谢您提供的信息,这很有趣,但我实际上并不是在寻找锁定的解决方案,我只是想了解我正在观察的行为。为什么有记录时读取成功,不存在记录时锁定?
  • “抑制”查询是否总是读取“未提交”插入的记录?
  • 我正在使用可序列化,但我只在一个事务中添加数据。选择只读取允许的数据。如您所述,可以读取易失性数据,但不能修改;我没有修改。
  • 读取表中已经存在的记录,不读取“未提交”的记录。
  • 问题可能来自“MAX”功能。它可能会尝试锁定“未提交”插入的记录。哎呀这个帖子here
猜你喜欢
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
  • 2021-01-28
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 1970-01-01
相关资源
最近更新 更多