SQL SERVER 行加锁问题

来源:互联网 发布:保健品护肤品淘宝店名 编辑:程序博客网 时间:2024/04/20 03:51

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/volcanoqcl/archive/2008/03/22/2207558.aspx

 

◆问题描述
想在检索一批数据的同时,加上更新锁,以禁止其他端末的更新。不是表级,页级加锁,自然而然想到了行级加锁。
但是,发现检索出来的记录以外的数据也被加上锁了。
◆问题分析
tabale
----------------------------------------------------
字段 C1(key1)  C2( key2)   C3  ............
       c1001          c2003         c3001  
       c1002          c2002         c3001
       c1003          c2001         c3001
索引 IX_TEST  (C2,C1)
----------------------------------------------------
用户A,用户B,公用部分SQL
set lock_timeout 0
begin transaction
select * from TEST with (index=IX_TEST,rowlock,updlock)
CASE①
用户A
where  C1 ='c1003'
结果-- c1003          c2001         c3001 (Locked)
用户B
where  C1 ='c1003'
结果-- 已超过了锁请求超时时段。 和预想的一样
where  C1 ='c1002'
结果-- 已超过了锁请求超时时段。 感觉这行也被锁住了
where  C1 ='c1001'
结果-- 已超过了锁请求超时时段。 感觉这行也被锁住了

分析--CASE①的结果来看,用户A对第三条数据加锁的同时,对第一第二条数据也加上锁了
     (这个不是我们预想的结果)
那我们再接着看。。。。。。。。。。。。。。。。。。。。
CASE②
用户A
where  C1 ='c1003'
结果-- c1003          c2001         c3001 (Locked)
用户B
where  C2 ='c2001'
结果-- 已超过了锁请求超时时段。 和预想的一样
where  C2 ='c2002'
结果--  c1002          c2002         c3001 (发现没有被用户A锁住)
where  C2 ='c2003'
结果-- c1001          c2003         c3001  (发现没有被用户A锁住)
分析--CASE②的结果来看,用户A只对第三条数据加了锁,其他两条没有被锁住
     (这符合我们预想的结果)
         
结合起来分析看,CASE①和CASE①的用户B只是用了不同的检索条件检索相同的记录,
但得出的加锁状态结果却不同。这是为什么呢?继续分析。。。
1.毫无疑问,首先,SQLSERVER的行级锁和表的索引有密切的关系,他是按照索引的顺序
去检索数据,并且在相应的记录上加锁。(默认索引是表的主键顺序-升序?)
2.查了一些论坛,有的是这么解释的,说是如果where条件中没有索引字段的相应条件的话
所有记录都会被上锁,相当于变成了表级锁。从上面的例子看不这么回事,锁还是该加在哪行就是在哪行的。
只不过是在第一次给某些记录加上了锁的基础上,再一次给这个表的某些记录去加锁的时候,SQLSERVER是
根据索引怎么去加锁的呢。上面的例子可以看出,不同的where条件,SQLSERVER去遍历记录的顺序是不同。
从两个case猜测,加锁的方式是,先根据WHERE条件确定在索引中位置. 遍历记录并给记录加锁,符合WHERE
中所用条件的记录情况下,就不解锁,如果不符合的话就解锁,这就把要加锁的记录加上了锁。
回头再看CASE①
索引  IX_TEST  (C2,C1)是先按字段C1,再是字段C2排序的,顺序如下
字段 C1(key1)  C2( key2)   C3  ............
       c1001          c2003         c3001  
       c1002          c2002         c3001
       c1003          c2001         c3001
用户B因为,用C1作为WHERE条件的C1 就无法准确的定位在索引位置,只能是从头到尾了,
这个时候它就会去遍历被用户A锁上的那条记录,因为已经锁上了,再加一次锁就会出现
【已超过了锁请求超时时段。】这个结果,貌似其他两条也被加上锁了。
CASE②的用户B因为能定位在索引中位置,所以没有再去遍历被用户A加上锁了的那条数据
所以能正确的检索出结果来。
======================================================================
总结,在操作行级别锁的时候,WHERE条件中必须要明确的确定在索引中位置的WHERE条件。
也就是说按照索引的顺序where C1 =,[C2=]。。。。

原创粉丝点击