疯狂的“独占”行锁
原文地址:
http://www.brokenwire.net/bw/Programming/115/the-madness-of-exclusive-row-locks
相关阅读:(2011-10-13)
消失的共享锁
译文:
昨天我发现了SQL SERVER一些确实很怪异的行为。我有一个案例我竟然可以读取被其他会话置了“独占”锁的记录。看到“独占”这个词,你想到的一定是:一个事务拥有独占行锁那么其它事务就不能读取该行了。但是这有特例:你可以读取被其它被别人独占锁定的行。
它花了我和同事很多时间,最终才发现到底是怎么回事。
为了重现这种行为,你需要一个测试表,表里有一些随机数据。
CREATE TABLE [MyTable]
([Col1] bigint PRIMARY KEY CLUSTERED, [Col2] bigint)
INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (1,10)
INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (2,20)
INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (3,30)
INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (4,40)
INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (5,50)
只要数据库没有打开快照隔离,你可以将测试表放在任何数据库中,而且恢复模式也对它没有影响。
下面我们来运行一些查询,看看会发生什么。为了能正确地测试,你需要对同一测试表运行两个不同的会话。为了能一直持有已分配的锁,你需要启动一个事务、运行一些命令,但是千万不要结束事务。
首先在查询分析器的第一个窗口中(我们称之为会话1)查询表中的某一行,并且使用提示XLOCK和ROWLOCK获得一个独占的行锁。
会话 1:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN
SELECT Col1 FROM [MyTable] WITH (XLOCK, ROWLOCK) WHERE [Col1] = 3
为了核实锁的情况,我们运行sp_locks来看看到底为会话1授予了哪些锁:
spid dbid ObjId IndId Type Resource Mode Status
------ ------ ----------- ------ ---- -------------------------------- -------- ------
56 21 69575286 1 PAG 1:41 IX GRANT
56 21 69575286 1 KEY (030075275214) X GRANT
56 21 69575286 0 TAB IX GRANT
你可以看到有一个“X”(独占)锁在表的第一个键上。(其他的锁是“IX”意向锁)。现在开始第2个连接,看看如果要读这条记录会发生什么?
会话 2:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN
SELECT Col1 FROM [MyTable] WHERE [Col1] = 3
我很希望这条语句被“挂住”,一直等到这条记录有效为止。但我吃惊地发现这条记录可以被非常顺利的读出。同时,sp_locks显示系统没有为这条指令分配任何其他锁,即使一个共享锁也没有。
如果你回滚会话2(为了撇清所有其它可能的情况)然后用表提示HOLDLOCK重新执行就会得到你想要的结果了:会话2中现在需要等待会话1中的事务完成了。
为了理解所发生的事,你需要回忆一下读提交隔离级别中的一条规则:可以读任何已经被提交的行。这里我们读的行时“干净的”(它没有被系统标为“脏的”),此时系统优化器会决定可以直接通过索引取数据而不需要检查锁的情况,所以表中甚至都不需要主键,只要有索引包含请求的数据,行锁就不需要了。
所以如果被锁住的记录并没有变化,被请求的列包含在索引中,那么从READ COMMITTTED隔离级别上就独占锁可能就没什么用了。
一种解决方法是在会话2的SELECT上加“HOLDLOCK”表提示。或者你也可以真的在会话1中更新记录,这样该记录就拥有独占锁了(而且还被标为“脏的”)。还有一种解决方法是用PAGLOCK锁住整个也而不仅仅是一行,此时独占锁会锁住该页中的所有行。
网上有人发了一篇帖子讲述了同样的怪异行为,一个微软员工回复道:
“在SELECT语句中使用XLOCK并不能阻止读。这是因为SQL SERVER在读提交隔离级别上有一种特殊的优化,即检查行是否已被修改,如果未被修改则忽略XLOCK。因为在读提交隔离级别上这确实是可以接受的。”
可能最糟糕的事是没能在联机图书上找到这种行为。哪怕在section about table hints中能有一个小小的说明也是好的。知识库KB324417中(适用于SQL SERVER 2000)只有一点点的提示。综合上面所有的事实,优化器选择这种行为比较随便,因此你的SQL代码中的BUG是很难被发现的。
结论:
这花了我很多时间来找出到底发生了什么事。所以记住:在SELECT语句中使用XLOCK和ROWLOCK提示并不意味着只有你一个人能读这些数据行。
分享到:
相关推荐
C API fopen打开的文件无法以独占方式操作文件,此代码利用Windows API巧妙的解决了该问题
1.此设计模拟满足设备独占性的独占设备的分配和回收。能够处理以下的情形: ⑴ 模拟设计的程序包括建立设备类表和设备表的程序段(在主函数中)、分配设备和回收设备的函数; ⑵ 分配设备要求输入作业名、设备类名...
打开被独占文件的方法,是进行技术调研、文件解析的必备技术!
独占设备的分配与回收,c++代码实现,有文档,操作系统设计。
清除 vss 独占工具 清除 vss 独占工具 清除 vss 独占工具
设计一种独占设备分配和回收的方案,要求满足设备独立性。使用编程语言(C或者C++)实现;当进程申请某类设备时,系统先查找“设备类表” 如果该类设备的现存台数可以满足申请要求,则从该类设备的“设备表”始址开始...
清除 vss 独占 工具 源码 清除 vss 独占 工具 源码 清除 vss 独占 工具 源码
操作系统课程设计 该程序实现了模拟独占设备的分配和回收。。
《卖油郎独占花魁》秦重形象分析.pdf
还原sqlserver2008数据提示:因为数据库正在使用,所以无法获得对数据库的独占访问权
独占设备的分配和回收 此实验模拟满足设备独占性的独占设备的分配和回收
统过模拟独占设备的分配和回收,了解操作系统对设备资源进行组织管理和分配、回收过程,掌握设备管理的思想。
vc查看某文件被谁独占打开了,仿Unlocker.zip
产品替代程度、独占交易与市场进入,安岗,李凯,本文基于Fumagalli & Motta(2006)的理论框架,将最终产品的替代程度引入独占交易模型中,重点讨论了产品替代程度对上游在位厂商提供排
打开被独占的文件方法.zip
断屏幕的四角是否属于同一个窗口句柄,判断当前系统是否处于全屏独占的模式
操作系统课程设计,详细的文档,内附有C编写的独占设备的分配与回收源代码与调试。
耳机按键在使用时,android一般通过广播方式进行发送,如果确保只有一个应用能处理此广播呢? 比如:在收听FM广播时,按下耳机hook键,此时会中断FM进行音乐播放,但用户的想法是希望能够暂停或恢复FM播放.
实现设备的添加,查询,更新,删除等操作....
gamedev.net的文章,由高手翻译了,讲解DirectX中全屏与窗口的模式切换实现