2011-08-23 71 views
1

我們有一個工作表。服務器代理作業在遊標中從該表抓取100個條目並執行一些工作。並行這個有10個服務器代理作業,其中撥打下列程序(每個都有自己的@process_id):由事務隔離級別分隔的併發進程死鎖

CREATE PROCEDURE sp_do_workorder @process_id INT 
AS 
BEGIN TRY 
    DECLARE @wo_id NCHAR(40), 
     @wo_action NVARCHAR(100), 
     @created_at DATETIME, 
     @source_proc_name NVARCHAR(100), 

    UPDATE procedure_ctrl SET [status]='running' WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='idle' 

    WHILE 1=1 
    BEGIN 
     IF NOT EXISTS (SELECT * FROM procedure_ctrl WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='running') BREAK 

     SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
     BEGIN TRANSACTION 
      UPDATE workorder SET hash=CAST(@process_id AS NVARCHAR(100)) 
      FROM workorder x 
      INNER JOIN (
       SELECT TOP 100 id FROM workorder WHERE hash='' AND workorder_step=0 ORDER BY created_at ASC 
      ) y ON x.id=y.id 
     COMMIT TRANSACTION 
     SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

     DECLARE wo_cur CURSOR FAST_FORWARD FOR SELECT id,action,created_at,optin_source FROM workorder WHERE hash=CAST(@process_id AS NVARCHAR(100)) AND workorder_step=0 ORDER BY created_at ASC 
     OPEN wo_cur 
     FETCH NEXT FROM wo_cur INTO @wo_id,@wo_action,@created_at,@source_proc_name 
     WHILE @@FETCH_STATUS=0 
     BEGIN 
      EXEC sp_basisprozess @wo_id,@wo_action,@created_at,@source_proc_name,@process_id 
      FETCH NEXT FROM wo_cur INTO @wo_id,@wo_action,@created_at,@source_proc_name 
     END 
     CLOSE wo_cur 
     DEALLOCATE wo_cur 

     WAITFOR DELAY '00:00:01' 
    END 

    UPDATE procedure_ctrl SET [status]='idle' WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='running' 
END TRY 
BEGIN CATCH 
    EXEC dbo.sp_listerror 
    DECLARE @error NVARCHAR(4000) 
    SET @error='[sp_do_workorder]_'+CAST(@process_id AS NVARCHAR(100))+': critical problem' 
    RAISERROR(@error, 12, 1)  
END CATCH 

我們得到一個真正的僵局往往大多數10個代理工作。有沒有人提示爲什麼這是這樣?爲了防止副作用,我們使用序列化事務隔離級別,因此只有一個代理作業可以抓取一個工作條目。在沒有設置事務隔離的情況下,死鎖就沒有了,但是經常發生,兩個(或更多)代理作業獲取相同的工作條目。

+2

請參閱[使用表格作爲隊列](http://rusanu.com/2010/03/26/using-tables-as-queues/) –

+0

聽起來不錯!我會試一試(並在稍後給出反饋) – rabudde

+0

這似乎完全符合我們的需要,真的很棒。請回答你的評論。 – rabudde

回答

2

我沒有試圖制定出具體原因僵局會發生在你的情況,但它好像能有效利用一個表作爲隊列在這種情況下看到this linked article爲法,即使用OUTPUT條款和鎖定提示最大限度地提高併發性而不會造成死鎖。