对表进行可序列化更新的最佳方法

时间:2009-02-24 14:37:16

标签: sql-server sql-server-2005

我是Firebird的长期用户,它有一个名为Generators的功能(我认为Oracle也有它,它叫做Sequences)。我是SQL Server的新手,我需要模拟相同的功能。我无法使用身份字段来解决我的问题。我需要一系列命名的值,而不是每行的唯一编号。

我最关心的是不止一个用户同时调用该过程并获取重复值,因此我决定使用SERIALIZABLE隔离级别进行锁定。

所以我提出了这个代码(我正在使用SQL Server 2005):

CREATE TABLE dbo.GENERATORS
    (
      [NAME] VARCHAR(30) NOT NULL,
      [VALUE] INT,
      CONSTRAINT UNQ_GENERATORS_NAME UNIQUE NONCLUSTERED ( [NAME] )
    )
GO

CREATE PROCEDURE GEN_ID
    (
      @GENERATOR_NAME VARCHAR(30)
    )
AS 
    DECLARE @RETURN_VALUE INT ;
    SET NOCOUNT ON
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    BEGIN TRANSACTION
    UPDATE  GENERATORS
    SET     [VALUE] = [VALUE] + 1
    WHERE   [NAME] = @GENERATOR_NAME
    IF @@ROWCOUNT = 0 
        BEGIN
            INSERT  INTO dbo.GENERATORS ( [NAME], [VALUE] )
            VALUES  ( @GENERATOR_NAME, 1 )
            SET @RETURN_VALUE = 1
        END
    ELSE 
        BEGIN
            SELECT  @RETURN_VALUE = [VALUE]
            FROM    GENERATORS
            WHERE   [NAME] = @GENERATOR_NAME
        END
    COMMIT TRANSACTION
    RETURN @RETURN_VALUE
GO

所以我的问题是:

  • 这是一个很好的解决方案吗?
  • 有没有更好的方法?

感谢。

1 个答案:

答案 0 :(得分:2)

而不是UPDATE和SELECT,要获得刚刚添加的值,您可以执行

UPDATE  GENERATORS
SET     @RETURN_VALUE = [VALUE] = [VALUE] + 1
WHERE   [NAME] = @GENERATOR_NAME

可能会消除对隔离级别的需求

我更希望将@RETURN_VALUE作为OUTPUT参数返回,而不是作为返回值 - 在执行期间为任何错误代码保留返回值。