用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
volcanoqcl的公告
文章分类
    存档

    原创  SQL SERVER 行加锁问题 收藏

    ◆问题描述
    想在检索一批数据的同时,加上更新锁,以禁止其他端末的更新。不是表级,页级加锁,自然而然想到了行级加锁。
    但是,发现检索出来的记录以外的数据也被加上锁了。
    ◆问题分析
    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=]。。。。
     

    发表于 @ 2008年03月22日 23:24:00 | 评论( loading... ) | 编辑| 举报| 收藏

    • 发表评论
    • 评论内容:
    •  
    Copyright © volcanoqcl
    Powered by CSDN Blog