并发检查失败时回滚事务

Rollback Transaction when concurrency check fails

我有一个存储过程,它对数据库进行大量探测以确定是否应更新某些记录

每条记录(订单)都有一个名为[RowVersion]

TIMESTAMP

我将候选记录 ID 和 RowVersions 存储在名为 @Ids

的临时 table 中
DECLARE @Ids TABLE (id int, [RowVersion] Binary(8))

我得到以下候选人的数量

DECLARE @FoundCount int
SELECT @FoundCount = COUNT(*) FROM @Ids

由于记录可能会从我 SELECT 到我最终尝试 UPDATE 时发生变化,我需要一种方法来检查并发性,如果检查失败 ROLLBACK TRANSACTION

我目前有什么

BEGIN TRANSACTION

-- create new combinable order group
INSERT INTO CombinableOrders DEFAULT VALUES 

-- update orders found into new group
UPDATE Orders
    SET Orders.CombinableOrder_Id = SCOPE_IDENTITY()
    FROM Orders AS Orders
    INNER JOIN @Ids AS Ids 
      ON Orders.Id = Ids.Id 
      AND Orders.[RowVersion] = Ids.[RowVersion] 

-- if the rows updated dosnt match the rows found, then there must be a concurrecy issue, roll back
IF (@@ROWCOUNT != @FoundCount)
BEGIN
    ROLLBACK TRANSACTION
    set @Updated = -1       
END
ELSE
    COMMIT

根据上面的内容,我正在使用存储的 [RowVersion] 过滤 UPDATE 这将跳过任何已更改的记录(希望如此)

但是我不太确定我是否在 TIMESTAMP 方面正确地使用事务或乐观并发,或者是否有更好的方法来实现我想要的目标

当您 SELECT 数据时,尝试在显式事务中使用 HOLDLOCK 和 UPDLOCK。它会扰乱其他事务的并发性,但不会扰乱你的事务。

http://msdn.microsoft.com/en-us/library/ms187373.aspx

很难理解您要实现的逻辑。

但是,如果您绝对必须在一个过程中执行多个非原子操作,并确保整个代码块在 运行 期间不会再次执行(例如,由另一个用户执行),考虑使用 sp_getapplock.

Places a lock on an application resource.

您的程序可能与此类似:

CREATE PROCEDURE [dbo].[YourProcedure]
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    BEGIN TRANSACTION;
    BEGIN TRY

        DECLARE @VarLockResult int;
        EXEC @VarLockResult = sp_getapplock
            @Resource = 'UniqueStringFor_app_lock',
            @LockMode = 'Exclusive',
            @LockOwner = 'Transaction',
            @LockTimeout = 60000,
            @DbPrincipal = 'public';

        IF @VarLockResult >= 0
        BEGIN
            -- Acquired the lock

            -- perform your complex processing

            -- populate table with IDs
            -- update other tables using IDs
            -- ...

        END;

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
    END CATCH;

END