begin tran
update EB with(rowlock) set Name='abc123' where Code=12 waitfor delay '00:00:13'
commit tran我用rowlock想锁定一行,可是它把整个表都锁定了。不管我更新哪一条数据都要等这条更新完毕。怎么才能锁定一条记录啊?

解决方案 »

  1.   

    SQL SERVER锁不住一行的,会升级为页级锁或表级锁。
      

  2.   

    update 好像本身会自己加行锁.
      

  3.   

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

  4.   

    where Code=12除非在修改的时候会涉及到这个条件的数据,要不应该不会影响的。
      

  5.   

    --不好意思,错了。这样可以锁住行的
    use pubs
    BEGIN TRAN
    UPDATE AUTHORS SET CITY=CITY+'D' WHERE AU_ID='274-80-9391'
      

  6.   

    [code=SQL]
    --先运行连接1,然后2
    --连接1
    BEGIN TRAN
    UPDATE AUTHORS SET CITY=CITY+'D' WHERE AU_ID='274-80-9391'--ROLLBACK TRAN--连接2:可以update 或 select,说明没有锁住其它行
    BEGIN TRAN
    UPDATE AUTHORS SET CITY=CITY+'D' WHERE AU_ID='341-22-1782'
    --SELECT * FROM AUTHORS--ROLLBACK TRAN[/code]
      

  7.   

    Name字段不是是参与了索引?
    如果Name参与了索引, Name的改动会涉及到索引的重新计算, 就会琐住整个表.
      

  8.   

    to:csdyyr就是利用事务未提交来实现锁。可是效果还是一样啊
    没有起到锁定一行效果,还是锁定了整个表。 
      

  9.   

    关键在于 update 语句在修改 Code=12 行前,需要扫描表搜索到 Code=12 行。rowlock 锁提示会指示系统在 update 语句扫描表时锁定扫描过的行,并保持到事务结束。如果锁定行达到一定数量,系统会将行锁升级为表锁。
      

  10.   

    SQLSERVER的行级锁和表的索引有密切的关系,
    如果表没有簇索引也没有唯一索引的话是无法使用行级锁
      

  11.   

    上午有事 下了。下午测试了一下。其实只要在 where 所使用的列上加上索引即可,就能达到行锁。
    begin tran
    update EC with(rowlock) set Name='abc123' where Code=21 waitfor delay '00:00:10'
    commit tran在Code 上加索引就能锁住这一行了。
      

  12.   

    创建索引后,UPDATE 语句将不使用表扫描,而使用索引搜索 Code=21 行。当然只会在该行加 KEY 锁。