存储过程中的SQLServer锁定表

问题描述

你们之间回答了我的问题。我要发表自己的答复,以整理我发表在一篇文章中的工作解决方案。关键似乎是事务处理方法,在last_auto_id表上具有锁定提示。将事务隔离设置为可序列化似乎会产生死锁问题。

这就是我所得到的(已编辑以显示完整的代码,因此希望我可以得到更多的答案…):

DECLARE @Pointer AS INT

BEGIN TRANSACTION

-- Check what the next ID to use should be
SELECT @NextId = LastId + 1 FROM Last_Auto_Id WITH (TABLOCKX) WHERE Name = 'CustomerNo'

-- Now check if this next ID already exists in the database
IF EXISTS (SELECT CustomerNo FROM Customer
           WHERE ISNUMERIC(CustomerNo) = 1 AND CustomerNo = @NextId)
BEGIN
  -- The next ID already exists - we need to find the next lowest free ID
  CREATE TABLE #idtbl ( IdNo int )

  -- Into temp table, grab all numeric IDs higher than the current next ID
  INSERT INTO #idtbl
  SELECT CAST(CustomerNo AS INT) FROM Customer
  WHERE ISNUMERIC(CustomerNo) = 1 AND CustomerNo >= @NextId
  ORDER BY CAST(CustomerNo AS INT)

  -- Join the table with itself, based on the right hand side of the join
  -- being equal to the ID on the left hand side + 1.  We're looking for
  -- the lowest record where the right hand side is NULL (i.e. the ID is
  -- unused)
  SELECT @Pointer = MIN( t1.IdNo ) + 1 FROM #idtbl t1
  LEFT OUTER JOIN #idtbl t2 ON t1.IdNo + 1 = t2.IdNo
  WHERE t2.IdNo IS NULL
END

UPDATE Last_Auto_Id SET LastId = @NextId WHERE Name = 'CustomerNo'

COMMIT TRANSACTION

SELECT @NextId

这将在事务开始时取出排他表锁,然后该表锁成功地将所有其他请求排队,直到此请求更新了表并提交了它的事务之后。

我编写了一些C代码,以将其与来自六个会话的并发请求一起使用,并且运行良好。

但是,我确实有个担心,那就是锁定“提示”一词-有人知道sqlServer是将其视为确定的指令还是仅作为提示(即,它可能不会始终服从它吗?)。

解决方法

我有一张桌子,我需要在99%的时间内自动分配ID(其他1%似乎使用身份列来排除)。因此,我有一个存储过程来获取以下行中的下一个ID:

``

select @nextid = lastid+1 from last_auto_id
check next available id in the table...
update last_auto_id set lastid = @nextid

检查必须检查用户是否手动使用了ID并找到下一个未使用的ID。

当我依次调用它并返回1、2、3时,它可以正常工作。我需要做的是在多个进程同时调用此方法的情况下提供一些锁定。理想情况下,我只需要它专用于围绕此代码锁定last_auto_id表,以便第二个调用必须等待第一个调用更新表才能运行它的select。

在Postgres中,我可以执行类似“ LOCK TABLE last_auto_id;”的操作 显式锁定表。有什么想法如何在SQL
Server中完成它吗?

提前致谢!