ALTER PROC [dbo].[getTopic]
(
    @uid INT
)
AS
        DECLARE @id uniqueidentifier
        BEGIN
        BEGIN TRAN
    SET ROWCOUNT 1
            SELECT @id=[id] FROM [topic] WITH(UPDLOCK, READPAST) WHERE [uid]=0
            --waitfor delay '00:00:01'
            if @@rowcount>0 BEGIN
               SELECT * FROM [topic] WHERE [id]=@id
               UPDATE [topic] SET [uid]=@uid WHERE [id]=@id
            END
        COMMIT TRAN
END
在当前存储过程执行中,当前记录不被别的连接访问,我不是很确定锁类型是否合理高并发不知道会不会出问题。
另外两个SELECT 一个赋值一个输出有没有办法合并成一个,会节约一些开支。

解决方案 »

  1.   

    不知道楼主的目的何在了
    当从上述语句觉得可以简化成:ALTER PROC [dbo].[getTopic]
    (
        @uid INT
    )
    AS
    DECLARE @id uniqueidentifier
    BEGIN
    UPDATE [topic] WITH(UPDLOCK, READPAST) SET [uid]=@uid WHERE [uid]=0
    END
      

  2.   

    READPAST
    指定数据库引擎不读取由其他事务锁定的行。在大多数情况下,这同样适用于页。如果指定了 READPAST,则行级锁和页级锁都将被跳过。也就是说,数据库引擎将跳过这些行或页,而不是阻塞当前事务直到锁被释放。例如,假定表 T1 包含一个单精度整数列,其值为 1、2、3、4 和 5。如果事务 A 将值 3 值改为 8,但尚未提交,则 SELECT * FROM T1 (READPAST) 将生成值 1、2、4 和 5。使用 SQL Server 表实现工作队列时,READPAST 主要用于减少锁定争用。使用 READPAST 的队列读取器会跳过被其他事务锁定的队列项,跳至下一个可用的队列项,而不是等待其他事务释放锁。可为 UPDATE 或 DELETE 语句中以及 FROM 子句中引用的任何表指定 READPAST。如果 READPAST 是在 UPDATE 语句中指定的,则仅当读取数据以标识要更新的记录时才应用 READPAST,而不考虑语句中指定 READPAST 的位置。不能为 INSERT 语句的 INTO 子句中的表指定 READPAST。使用 READPAST 的读操作不会发生阻塞。读取外键或索引视图或者修改辅助索引时,使用 READPAST 的更新或删除操作可能发生阻塞。仅可在运行于 READ COMMITTED 或 REPEATABLE READ 隔离级别的事务中指定 READPAST。在从 SNAPSHOT 隔离级别操作的事务中指定时,READPAST 必须与需要锁的其他表提示(例如,UPDLOCK 和 HOLDLOCK)组合。当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 并且满足以下条件之一时,无法指定 READPAST 表提示。会话的事务隔离级别为 READ COMMITTED。
    查询中也指定了 READCOMMITTED 表提示。
    若要在上述情况下指定 READPAST 提示,请删除 READCOMMITTED 表提示(如果存在),然后在查询中包括 READCOMMITTEDLOCK 表提示。
      

  3.   

    确保被一个用户拿走以后更新 uid不等于0 别的用户就取不走。
      

  4.   

    其实这个应该就是丢失更新的错误,兼容级别的repeatable read可以解决这个问题。或者你自己锁定资源。
      

  5.   

    ALTER PROC [dbo].[getTopic]
    (
        @uid INT
    )
    AS
    DECLARE @id uniqueidentifier
    BEGIN
    BEGIN TRAN
    SET ROWCOUNT 1
        SELECT @id=[id] FROM [topic] WHERE [uid]=0
       if ISNULL(@id,0)>0 BEGIN
          UPDATE [topic] SET [uid]=@uid WHERE [id]=@id
           if (@@ERROR<>0)
           begin
    ROLLBACK TRAN
    RETURN
           end       
        END
    COMMIT TRAN
    END
      

  6.   

    你没有必要在查询时加锁,可以改得更简单:
    ALTER PROC [dbo].[getTopic] @uid INT 
    AS
    DECLARE @id uniqueidentifier
    BEGIN
    SELECT @id=[id] FROM [topic] WHERE [uid]=0
    if ISNULL(@id,0)>0 
    BEGIN
    BEGIN TRAN
        UPDATE [topic] SET [uid]=@uid WHERE [id]=@id
        if (@@ERROR<>0)
    ROLLBACK TRAN
    else
    COMMIT TRAN
    END END go