2017-07-22 168 views
0

我有一個.Net應用程序用於表單處理,它可以跨三個不同的SQL Server 2012數據庫刪除/更新/插入數據。當應用程序運行時,它會爲每個需要處理的表單打開一個數據上下文,然後在該上下文中創建一個事務(每分鐘運行一次,因此一次只能有一個表單)。一堆東​​西發生在這個事務中 - 包括多個存儲的proc調用。SQL-服務器事務阻止神祕

所以這裏的問題:

我們已經設置了什麼,我告訴服務器是完全相同的規格(雖然我懷疑:))。一個用於開發工作;另一個用於客戶端測試。在我們的開發環境中,處理過程毫無問題;但在客戶端測試網站上,它每次都會掛起。我正在拉我的頭髮,試圖確定爲什麼。

在以下TSQL代碼中,它是插入Param表失敗。除了列名之外,Param表基本上與Method表相同。兩個插入都與Form表具有相似的外鍵關係,並且都將int值插入到ID列中。

當我運行SQL Server Profiler時,我被告知FormDB上有一個不允許插入的鎖。不過,我可以改變Param插入的select語句,它可以工作。我已經改變了在以下幾個方面,都在意義上的「工作」的,他們不引起堵塞的問題:

  • 取代了帕拉姆選擇與方法選擇,同時保持所述插件參數(確切相同的列表示參數選擇)
  • 將@ newKey替換爲現有表單的有效整數。
  • 刪除了「從」帕拉姆的部分選擇和硬編碼的芳族聚酰胺單int值(即選擇@newKey,1,@modifyDate,@modifyUser)

我覺得我失去了我因爲我不明白爲什麼它不起作用。只有組合select語句中的三件事情時,insert纔會失敗 - @ newKey,ParamID和from語句。

我確保每個sproc都有SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,並且在必要時與nolock一起使用。

爲什麼我可以通過上述三種方案成功地插入Param表中,但是後面代碼中的參數插入失敗?爲什麼我不會在分析器中收到相同的鎖定消息?在此過程中還有大約5個其他插頁遵循相同的模式。他們都工作沒有問題。

任何想法?謝謝。

USE [PROD] 
GO 

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE [dbo].[HELPSPROC] 
    @oldKey int 
AS 

BEGIN 
    SET NOCOUNT ON; 
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

    declare @newKey int 
    , @spKey int 
    , @modifyDate datetime = getdate() 
    , @modifyUser varchar(30) = 'User' 

/* 
a bunch of stuff happens here, including setting the @spKey value. 
this all happening correctly -- we have a valid integer value when we go into the next part 
*/ 

---------------FORM--------------- 
INSERT INTO FormDB.dbo.Form 
    (formtype, formstatus, modifydate, modifyuser) 
Select 
    'TestFormType', 'DRAFT', @modifyDate, @modifyUser        
From FormDB2.dbo.Form f 
Where f.Pkey = @oldKey 

--grab the new int identifier -- works      
set @newKey = (select scope_identity()) 

/* 
stuff happens here. all is good in this part 
*/ 


---------------Param--------------- 
INSERT INTO FormDB.dbo.Param 
    (FormKey, ParamID, ModifyDate, ModifyUser) 
select @newKey, p.ParamID, @modifyDate, @modifyUser 
from PROD.dbo.Table1 apd 
    inner join PROD.dbo.ParameterTable p 
     on apd.TableTwoKey = p.TableTwoKey 
where apd.PKey = @spKey 



---------------Method--------------- 
INSERT INTO FormDB.dbo.Method 
    (FormKey, MethodID, ModifyDate, ModifyUser) 
select @newKey, r.MethodID, @modifyDate, @modifyUser 
from PROD.dbo.Table1 apd 
    inner join PROD.dbo.MethodTable r 
     on apd.TableTwoKey = r.TableTwoKey 
where apd.PKey = @spKey 

/* 
one more insert ... 
*/ 


RETURN 1 

END 

GO 
+0

你是什麼意思「有一個鎖在FormDB上」? – Alex

+0

Hi @Alex。從我使用SQL Profiler,活動監視器和[Microsoft](https://support.microsoft.com/en-us/help/271509/how-to-monitor-blocking-in- sql-server-2005-and-in-sql-server-2000),我可以看到一個SPID(狀態爲睡眠狀態並等待命令)阻止當前插入另一個SPID(掛起狀態)。 –

回答

0

我還是不明白這個問題的爲什麼,但我找到了解決辦法。

在這個過程的vb.net代碼中發生了很多事情:多個linq-to-sql在三個獨立的數據庫中插入/刪除/更新,以及兩個單獨的存儲過程調用。爲了增加混淆,每個數據庫都有獨立的上下文,每個數據庫都有自己的事務。總之,一堆運動部件。

第二次存儲的proc調用是有條件的,基於處理表單的某些值。我剛剛從vb中接過這個電話。網絡代碼,並將條件邏輯和proc調用存儲在第一個proc中。這解決了它。第二個存儲過程在第一個之後直接調用 - 等待條件 - 因此一切都很好。

問題已解決 - 但如果有人能解釋爲什麼會發生這種情況,我會很感激。謝謝!

+0

我的猜測:您可能在某處有未提交的交易。如果您使用鏈接服務器,請檢查「啓用分佈式事務的提升」設置是否相同。 – Alex

+0

太好了。感謝提示@Alex! –