【问题标题】:T-SQL stored procedure getting same value several times from counterT-SQL 存储过程从计数器多次获取相同的值
【发布时间】:2011-05-26 11:16:47
【问题描述】:

我创建了一个存储过程,它应该通过每次调用表中的值递增来返回一个唯一的数字。

ALTER PROCEDURE [dbo].[GetNextNumber] @Next_Number char(9) output AS
BEGIN
    BEGIN TRAN

    DECLARE @Current_Number int
    SET @Current_Number = (SELECT CONVERT(int, Counter) FROM CounterTable)

    IF(@Current_Number IS NULL)
    BEGIN
        SET @Next_Number = '000000000'
        INSERT INTO CounterTable (Counter) VALUES (@Next_Number)
    END
    ELSE IF(@Current_Number >= 999999999)
    BEGIN
         SET @Next_Number = '000000000'
         UPDATE dbo.CounterTable SET Counter = @Next_Number
    END
    ELSE
    BEGIN
        SET @Next_Number = REPLACE(STR(@Current_Number + 1, 9),' ', '0')
        UPDATE dbo.CounterTable SET Counter = @Next_Number
    END

    COMMIT TRAN
END

有时存储过程会返回相同的数字两次。我做错了什么?

【问题讨论】:

  • 您是否有多个进程/线程访问此过程?
  • 您是在循环客户端还是在另一个 proc 中调用此 proc?
  • 发生的频率是多少?
  • 是的,该过程由可以在多个实例中运行的 C# 组件访问。但我认为当我在事务中运行 proc 时这并不重要。

标签: sql sql-server tsql stored-procedures


【解决方案1】:

我以前做过:

update CounterTable set @Next_Number = Counter = Counter + 1

它将它保存在一个语句中,因此(除非您切换到未提交的读取,可能)不应该有多个调用者的问题。

【讨论】:

  • +1 这很可能也足以解决 OP 的问题。
  • 我实际上切换到了这个实现,因为它与我的 C# 组件配合得更好。
【解决方案2】:

您可以使用Table Hints 显式锁定Countertable

...
SET @Current_Number = (
   SELECT CONVERT(int, Counter) 
   FROM CounterTable WITH(Holdlock, Updlock)
)
...

【讨论】:

  • 当事务块存在并且正在使用存储过程时是否有可能面对这种行为?如果多个用户访问同一个 Proc,系统将创建相同数量的实例。
  • @SQL - HoldLock 选项等同于 Serializable。本质上,您正在创建一个狭窄的管道,从头到尾只有一个线程可以通过。
  • 我会试试这个。我在重现问题时遇到了一些问题,因为这发生在生产环境中,当他们处理大量时。但是我还是不明白,当你在一个事务中完成所有事情时,怎么会发生这种情况?
  • @user682728 - 这取决于您的transaction isolation level,但使用默认级别,您的begin transaction 确实阻止其他线程读取 CounterTable 中的计数器。
猜你喜欢
  • 2011-02-22
  • 2017-08-18
  • 2011-05-04
  • 2010-09-07
  • 1970-01-01
  • 2021-04-22
  • 2018-10-03
  • 2013-05-28
  • 1970-01-01
相关资源
最近更新 更多