2015-01-16 66 views
0

我有一个存储过程,它不会对数据库的探测,以确定一些记录应更新当并发检查失败

的很多每个记录(订单)具有TIMESTAMP称为[RowVersion]

我回滚事务存储候选记录ID和RowVersions在临时表称为@Ids

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 

从上面,我正在过滤UPDATE与存储[RowVersion]这将跳过任何记录已经被改变(希望)

但是我不太清楚,如果我正确地使用事务处理或乐观并发关于TIMESTAMP我,或者有更好的方法来达到我的预期目标

回答

0

这很难理解你试图实现什么逻辑。

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

锁定应用程序资源。

你的程序可能类似于此:

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 
+0

感谢我在SP –

+0

年底做一个更新之前你的答案但是实际上我试着去确定一些其他的查询顺序改变了我再次重读您的问题。它在我看来你在做什么是正确的。 MSDN ['rowversion'](https://msdn.microsoft.com/zh-cn/library/ms182776.aspx)文章有一个例子,他们在'UPDATE'语句中使用'OUTPUT'子句。他们记得在一个单独的表变量中更新的行,然后用它来计算更新了多少行。你为此使用'@@ ROWCOUNT'。我不知道哪种方法更好。如果您确实想要在处理过程中一起更新多个订单,那么您的解决方案应该可以正常工作。 –