存储过程中的SQLServer锁表

asc*_*99c 8 sql sql-server locking

我有一个表,我需要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中完成它?

提前致谢!

Lie*_*ers 5

更新后,将lastid增加1,并在单个事务中将此值分配给本地变量.

编辑

感谢Dave和Mitch指出原始解决方案的隔离级别问题.

UPDATE  last_auto_id WITH (READCOMMITTEDLOCK)
SET     @nextid = lastid = lastid + 1
Run Code Online (Sandbox Code Playgroud)


asc*_*99c 4

你们之间已经回答了我的问题。我正在添加自己的回复,以整理我在一篇文章中得到的工作解决方案。关键似乎是事务方法,在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
Run Code Online (Sandbox Code Playgroud)

这会在事务开始时取出独占表锁,然后成功地将任何进一步的请求排队,直到该请求更新表并提交其事务之后。

我编写了一些 C 代码来处理来自六个会话的并发请求,并且它工作得很好。

然而,我确实有一个担心,那就是术语锁定“提示” - 有谁知道 SQLServer 是否将其视为明确的指令或只是一个提示(即也许它不会总是遵守它??)