3

我有一个存储程序,

ALTER PROCEDURE [dbo].[InsertDealGallery] 
(
    @ImageID INT,
    @DealID INT
)
AS

    DECLARE @MaxOrder INT;
    SELECT @MaxOrder = MAX([Order]) + 1 FROM DealGallery WHERE DealID = @DealID

    IF (@MaxOrder IS NULL)
    BEGIN
        SET @MaxOrder = 1;
    END



   INSERT INTO [DealGallery]
                ([ImageID]
                ,[DealID]
                ,[Order])  
        VALUES
                (@ImageID
                ,@DealID
                ,@MaxOrder)

但我担心这不是原子的,因为同时 MaxOrder 在并发线程中可能保持不变。那么如何使这个原子?

4

3 回答 3

3

事务是获得原子行为的特征。你知道 a from ACID 是 Atomic 的。但是你选择了一个很糟糕的设计,聚合功能可以锁定所有行,性能变得很差。

已编辑

您应该转到 identitat 数据类型。还存在另一种技术,例如计数器表,但简单的方法是身份。

要将代码包含在事务中,您应该包含“开始事务”和“提交”语句。

已编辑 2

这种方法,每个都有一个计数器Deal,将避免锁定所有DealGallery的行,只锁定DealGalleryCounter行。

CREATE TABLE DealGalleryCounter 
  (DealID INT not null primary key,
   order int default 0
  );   -- Or add column to an existing deal table. 

ALTER PROCEDURE [dbo].[InsertDealGallery] 
(
    @ImageID INT,
    @DealID INT
)
AS BEGIN
    DECLARE @order int

    begin transaction
    set transaction isolation level serializable
    -- repeatable read is enough --

    select @order = order + 1
      from DealGalleryCounter 
     where @DealID = DealID

    if @order is null
      insert into DealGalleryCounter (DealID) values (@DealID)

    INSERT INTO dbo.DealGallery (ImageID, DealID, [Order])  
    VALUES ( @ImageID, @DealID, @order );

    update DealGallery 
       set DealGalleryCounter = @order
     where @DealID = DealID;

    commit;    --or check for errors and rollback
END
于 2013-06-12T07:14:43.933 回答
1

试试这个——

ALTER PROCEDURE [dbo].[InsertDealGallery] 
(
    @ImageID INT,
    @DealID INT
)
AS BEGIN

    INSERT INTO dbo.DealGallery (ImageID, DealID, [Order])  
    SELECT 
          @ImageID
        , @DealID
        , ISNULL(MAX(d.[Order]) + 1, 1)
    FROM (SELECT a = 1) t
    LEFT JOIN dbo.DealGallery d ON d.DealID = @DealID

END

或者试试这个——

INSERT INTO dbo.DealGallery (ImageID, DealID, [Order])  
    SELECT 
          @ImageID
        , @DealID
        , ISNULL(m, a)
    FROM (SELECT a = 1) t
    LEFT JOIN (
        SELECT m = MAX(d.[Order]) + 1
        FROM dbo.DealGallery d 
        WHERE d.DealID = @DealID
    ) t2 ON 1 = 1
于 2013-06-12T07:22:33.507 回答
0

这应该有效:当在 DealGallery 表中找到交易 ID 时插入最大订单增加一,否则将最大订单插入为 0

BEGIN TRAN

  INSERT INTO [DealGallery]
                  ([ImageID]
                  ,[DealID]
                  ,[Order])
  SELECT @ImageID, @DealID, MAX([Order]) + 1
  FROM DealGallery WHERE DealID = @DealID
  UNION
  SELECT @ImageID, @DeadID, 1
  FROM (SELECT 1 AS C) AS T
  WHERE NOT EXISTS (SELECT * FROM DealGallery WHERE DealID = @DealID)

COMMIT TRAN
于 2013-06-12T07:13:01.700 回答