0

我读过关于微软的网站 http://msdn.microsoft.com/en-us/library/ms173763.aspx共享锁和快照隔离

读取数据时,当数据库被恢复,除了SQL Server不要求锁。

这是否意味着使用READ_COMMITTED_SNAPSHOT/SNAPSHOT ISOLATION的Sql Server根本不使用共享锁? 这怎么可能?

例如,如果有2个交易。 第一个事务T1想要更新某一行。 第二个事务T2开始读取同一行(此事务将他复制到某个输出缓冲区,响应缓冲区或任何在Sql Server中调用的事务)。 与此同时,事务T1开始更新该行(它首先创建了版本化行)。

事务T2是否有可能读取未被取消的数据?请记住,事务T2在T1更新之前开始复制该行,因此该行没有排它锁。

这种情况甚至是可能的吗?如何在避免在复制数据时设置共享锁的情况下避免这种情况?

回答

2

除了逻辑锁也有物理latches保护数据库结构(特别是在这个例子中,页面)。锁存器保护任何更改(位的修改),与隔离级别无关。因此,即使T1没有获取锁,它仍然需要在它读取的页面上获取共享锁存器,否则它将成为对其读取的结构进行低级并发修改的牺牲品。T2可以修改包含它修改的行的页面,只有当它获得一个页面专用锁存器。因此,T1只能在T2修改之前看到该行的图像(因此行是T1想要的行),或者在T2完成后对行进行修改(现在T1必须查找上一行图像version store)。

锁存协议必须符合所有隔离级别,包括读取未提交和版本化读取(即快照和朋友)。

+0

因此,每次某个事务正在读取数据时,它会在读取数据期间在完成页面上获取锁存并在完成后立即释放锁存器? – Marka

+0

查看[白羊座论文1.4章](http://www.cs.berkeley.edu/~brewer/cs262/Aries.pdf) –

0

这是否意味着使用READ_COMMITTED_SNAPSHOT/SNAPSHOT ISOLATION的Sql Server根本不使用共享锁?这怎么可能?

因为SQL Server是从快照,它是不会通过任何改变走在所有阅读它是可能的。已经在当前交易开始时在DB的状态下已冻结冻结,忽略来自其他进程的未提交交易。这是通过SQL Server保留快照row-versionedtempdb中的记录的副本以使事务处理引用,使当前正在进行的数据/索引页面发生更改。

事务T2是否有可能读取未被取消的数据?请记住,在T1进行更新之前,事务T2开始复制该行,因此该行没有排它锁。

以上叙述已经解释了这一点。而是为了说明(简化):

方案1:

T1: begin tran (implicit/explicit) 
T1: read value (4) 
T2: read value (4) -- * 
T1: update value to (8) 

* - This is the committed value at the time the T2 transaction started 

方案2:

T1: begin tran (implicit/explicit) 
T1: read value (4) 
T1: update value to (8) 
    version of the row with the value (4) is made 
T2: read value (4) -- * from the versioned row 
T1: commit 

* - (4) is [still] the *committed* value at the time the T2 transaction started 
+0

我不确定当SNAPSHOT ISOLATION打开时,Sql Server复制8K页面时某些行被更改。您可能会参考数据库快照。他改为创建存储在tempdb中的行版本。该行上的任何更新都是在原始页面上进行的。所以,当选择开始复制数据时,更新将会改变到正在复制的同一位置。 – Marka

+0

我对第三种场景感兴趣,当T2开始更新T1时主动读取行。这种情况可能吗? – Marka

+0

这是不可能的。行版本复制在数据更新之前完成。在某个时间点,两个副本都包含相同的信息,这是检索快照隔离进程的正确信息。 – RichardTheKiwi