select * from table with(加锁方式)

解决方案 »

  1.   

    锁定提示 描述 
    HOLDLOCK 将共享锁保留到事务完成,而不是在相应的表、行或数据页不再需要时就立即释放锁。HOLDLOCK 等同于 SERIALIZABLE。 
    NOLOCK 不要发出共享锁,并且不要提供排它锁。当此选项生效时,可能会读取未提交的事务或一组在读取中间回滚的页面。有可能发生脏读。仅应用于 SELECT 语句。 
    PAGLOCK 在通常使用单个表锁的地方采用页锁。 
    READCOMMITTED 用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。 
    READPAST 跳过锁定行。此选项导致事务跳过由其它事务锁定的行(这些行平常会显示在结果集内),而不是阻塞该事务,使其等待其它事务释放在这些行上的锁。READPAST 锁提示仅适用于运行在提交读隔离级别的事务,并且只在行级锁之后读取。仅适用于 SELECT 语句。 
    READUNCOMMITTED 等同于 NOLOCK。 
    REPEATABLEREAD 用与运行在可重复读隔离级别的事务相同的锁语义执行扫描。  
    ROWLOCK 使用行级锁,而不使用粒度更粗的页级锁和表级锁。 
    SERIALIZABLE 用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。 
    TABLOCK 使用表锁代替粒度更细的行级锁或页级锁。在语句结束前,SQL Server 一直持有该锁。但是,如果同时指定 HOLDLOCK,那么在事务结束之前,锁将被一直持有。 
    TABLOCKX 使用表的排它锁。该锁可以防止其它事务读取或更新表,并在语句或事务结束前一直持有。 
    UPDLOCK 读取表时使用更新锁,而不使用共享锁,并将锁一直保留到语句或事务的结束。UPDLOCK 的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改。 
    XLOCK 使用排它锁并一直保持到由语句处理的所有数据上的事务结束时。可以使用 PAGLOCK 或 TABLOCK 指定该锁,这种情况下排它锁适用于适当级别的粒度。 
      

  2.   

    1. 把select放在事务中, 否则select完成, 锁就释放了
    2. 要阻止另一个select , 则要手工加锁, select 默认是共享锁, select之间的共享锁是不冲突的, 所以, 如果只是共享锁, 即使锁没有释放, 另一个select一样可以下共享锁, 从而select出数据BEGIN TRAN
    SELECT * FROM tb WITH(TABLOCKX)
    UPDATE ....
    COMMIT TRAN
      

  3.   

    BEGIN TRAN
            -- 事务不提交或者回滚, 以保持锁不释放SELECT * FROM tb WITH(UPDLOCK, READPAST)        -- UPDLOCK 让锁保留到事务结束, READPAST 跳过已经锁定的数据
      

  4.   

    感谢各位的回复,不过我还是不太明确:我希望我每次select产生的锁定不会导致下一次select失败或等待,也就是仅锁定一条记录,下一次select仍然能够立刻顺利地获得另一条记录使用事务好像不能解决问题,它只能保证当两次调用事务select到同一条记录时,其中一次事务会因为update失败而失败,所以我需要使用一个循环来执行事务直到成功。这与我的需求不符,如果仅仅为了保证每一次select得到不同的记录而不用考虑效率,那么我完全可以使用队列排队,而不是多线程并发
      

  5.   

    我希望我每次select产生的锁定不会导致下一次select失败或等待,也就是仅锁定一条记录,下一次select仍然能够立刻顺利地获得另一条记录
    =====================================================
    select 产生的锁导致下一次select失败或者等待? 你是指并发中的另一个线程吧?
    如:
    real_name(*真名) ( ) 信誉:100    Blog 
    已经写了, 再加 READPAST 选项, 可以跳过已经锁的行, 这样, 无论你用几个线程, 那么SELECT都不会被阻塞, 它始终去读取未被锁定的行.
      

  6.   

    至于锁定多少条记录的问题, sql默认的锁定行为本来就是行级锁定的, 所以你用TOP 1指定只锁定一条记录就好了/SELECT TOP 1 * FROM tb WITH(UPDLOCK, READPAST)
      

  7.   

    下一次select仍然能够立刻顺利地获得另一条记录这个问题跟你的处理逻辑有关, 在处理的记录, 已经用锁定来标识了, 你必须能够标识在你的查询方法中, 能够通过条件过滤掉已经处理完成的记录, 这个是你自己处理的时候应该考虑的问题, 与锁无关.
      

  8.   

    SELECT * FROM tb WITH(TABLOCKX) 
    //这样做会产生应用瓶颈,好比让一条16车道的马路连接一座单车道的桥,马路再宽也要堵车的SELECT * FROM tb WITH(UPDLOCK, READPAST)
    //这样的锁能对select产生影响吗?
      

  9.   

    不好意思,编辑回帖时没看到新回复to zjcxc:其实关键找不到合适了型的锁啊TABLOCKX锁掉了整张表,肯定不能用;UPDLOCK是更新锁,对select没有约束力
      

  10.   

    UPDLOCK是更新锁,对select没有约束力---------------------------楼主想约束的SELECT, 应该只限于你的SELECT后有更新的那此SELECT吧?
    如果是那样的话, 那就不存在问题了, 因为有UPDATE的SELECT, 你都使用UPDLOCK, 这样下的都是更新锁, 而更新锁与更新锁是有冲突的, 所以是有约束力的.
      

  11.   

    如果要阻塞所有的SELECT, 则可以用 XLOCK,PAGLOCK 来下页级的排它锁
      

  12.   

    to zjcxc:假如我并发调用以下过程多次:select top 1 X from Table_A with(updlock, readpast) where Y=0
    update Table_A set Y=1 where X=x请你明确告诉我:有没有可能有两次select到同一条记录?我认为这样加锁,实际上只是防止了两次update同一条记录
    而并不会防止两次select同一条记录在select上加锁导致update失败从而间接导致整个过程失败,这并不是我需要的结果
    因为这样仅仅保证了功能需求,而对性能需求是起反作用的
    我必须增加额外的循环开销来处理如果失败
    这样的话我还不如放弃并发,老老实实地等待update成功了再select
      

  13.   

    select * from tb with(tablockx)
      

  14.   

    set rowcount 1                               -- 设置取最新一条记录
    begin tran
    update table set @X=x,flag=1 where flag=0    -- 取出同时设置已读
    commit tran
    select @X
      

  15.   

    select top 1 X from Table_A with(updlock, readpast) where Y=0
    update Table_A set Y=1 where X=x看你的两次怎么算, 如果第1次的已经提交事务了, 第2次的select才发出, 则第2次很有可能取得第1次的记录, 否则是不可能的.
      

  16.   

    这也是我提到的另一个问题:下一次select仍然能够立刻顺利地获得另一条记录这个问题跟你的处理逻辑有关, 在处理的记录, 已经用锁定来标识了, 你必须能够标识在你的查询方法中, 能够通过条件过滤掉已经处理完成的记录, 这个是你自己处理的时候应该考虑的问题, 与锁无关.
      

  17.   

    select top 1 X from Table_A where Y=0 FOR UPDATE
    取值的时候就锁表,然后接着更新.
    update Table_A set Y=1 where X=x
      

  18.   

    吼吼
    我爱钻石
    吼吼select X from Table_A where Y=0 for update//行锁,选中多少行纪录锁多少行纪录在遇到commit 或 rollback后解锁
      

  19.   

    呵好问题呀!我前段时间也遇到了这种问题.进来学习一下MARK
      

  20.   

    select top 1 X from Table_A with(updlock, readpast) where Y=0
    update Table_A set Y=1 where X=x看你的两次怎么算, 如果第1次的已经提交事务了, 第2次的select才发出, 则第2次很有可能取得第1次的记录, 否则是不可能的.zjcxc(邹建):不明白你说的这句话呀!
    如果第1次的已经提交事务了, 第2次的select才发出, 则第2次很有可能取得第1次的记录
    他那个SELECT是有条件限制的就是说第一次事务结束之后Y就等于1了.按道理来说第二次是不应该取到重复的呀!
      

  21.   

    real_name(*真名)的是正解,楼主可以执行一下试试.
    BEGIN TRAN
            -- 事务不提交或者回滚, 以保持锁不释放SELECT * FROM tb WITH(UPDLOCK, READPAST)
            -- UPDLOCK 让锁保留到事务结束, READPAST 跳过已经锁定的数据sp_locks @@spid
            -- 查看被锁定的资源