2013-03-25 49 views
0

我已經在C#中創建了兩個線程,我並行地調用了兩個單獨的函數。這兩個函數都從XYZ表中讀取最後一個ID,並插入值爲ID + 1的新記錄。這裏ID列是主鍵。當我執行這兩個函數時,我得到主鍵違規錯誤。這兩個函數具有以下查詢:在SQL Server 2008中的主鍵違規錯誤

insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

似乎這兩個函數都在讀取值,並嘗試插入具有相同的值。 我該如何解決這個問題..?

+0

好, Java有一個同步關鍵字來防止多個線程互相干擾。我建議你在C#中查找類似結構的多線程鏈接。 – 2013-03-25 04:26:53

+0

@ChetterHummin不,他的問題是他試圖找出在應用程序中插入的ID,當他應該讓數據庫處理它時。是的,他也可以創建共享和同步的ID變量,但這不會阻止數據庫同步的問題。例如,考慮第三方插入到他的表中的問題,該表沒有使用他的共享變量。然後他仍然有同樣的問題。 – KyleM 2013-03-25 04:30:42

+0

@KyleM感謝您的澄清!以上查詢爲 – 2013-03-25 04:31:20

回答

2

讓數據庫處理爲您選擇ID。從上面的代碼可以看出,你真正想要的是一個自動遞增的整數ID列,數據庫肯定能夠爲你處理。所以設置你的表正確,而是你目前的INSERT語句,這樣做:

insert into XYZ values('Name') 

如果數據庫表已經建立了,我相信你可以發出類似聲明:

alter table your_table modify column you_table_id int(size) auto_increment 

最後,如果這些解決方案都不能滿足任何原因(包括,正如您在評論部分中所指出的,無法編輯表模式),那麼您可以作爲註釋中建議的其他用戶之一併創建一個同步方法來查找下一個ID。基本上只需創建一個返回int的靜態方法,在該靜態方法中發出您的select id語句,並使用返回的結果將下一條記錄插入到表中。由於此方法不能保證插入成功(由於外部應用程序也能夠插入到同一個表中),所以您還必須捕獲異常並在失敗時重試)。

+0

就是一個例子。其實它的表格超過50個字段和主鍵字段不是自動增量。我們必須明確插入唯一值。 – Irappabi 2013-03-25 04:33:32

+0

@ user1365604那麼也許你應該解釋你的主鍵是如何工作的。從你迄今爲止解釋的內容來看,肯定應該是一個增量欄。 – KyleM 2013-03-25 04:35:08

+0

@ user1365604爲什麼你必須明確插入它?爲什麼你不能糾正你的數據庫表的設計爲你自動增加?你知道'改變'聲明是什麼嗎? – KyleM 2013-03-25 04:38:02

2

將ID列設置爲「標識」列。然後,你可以執行你的查詢爲:

insert into XYZ values('Name') 

我認爲你不能使用ALTER TABLE來更改列是身份創建列之後。使用Managament Studio將此列設置爲Identity。如果你的表有很多行,這可能是一個長時間運行的過程,因爲它實際上將你的數據複製到一個新表(將執行表重新創建)。

最有可能在您的Managament Studio中禁用此選項。爲了使它打開工具 - >選項 - >設計器,並取消選中「防止保存需要重新創建表的更改」選項...根據您的表大小,您可能也必須設置超時。在此期間你的桌子將被鎖定。

0

解決這些問題的方法是使用某種序列生成ID。

例如,在SQL Server中,你可以使用下面的命令來創建一個序列:

CREATE SEQUENCE Test.CountBy1 
    START WITH 1 
    INCREMENT BY 1 ; 
GO 

然後在C#中,你可以從測試的檢索下一個值,並將其插入之前分配給該ID。

+1

序列僅在SQL Server 2012中可用; OP正在使用2008年沒有該功能。 – Gabe 2013-03-25 05:03:14

+0

謝謝Gabe,不知道。以下帖子提示「IDENTITY」專欄。 http://stackoverflow.com/questions/7238816/cant-create-sequence-in-sql-server-2008 – 2013-03-25 19:31:50

0

這聽起來像你想要更高transaction isolation level或更多限制locking

我不使用這些功能過於頻繁,所以,如果我錯了,希望有人會提出修改建議,但希望其中之一:

-- specify the strictest isolation level 
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

-- make locks exclusive so other transactions cannot access the same rows 
insert into XYZ values((SELECT max(ID)+1 from XYZ WITH (XLOCK)),'Name') 
+0

我不明白downvote,更高的事務隔離級別可以幫助這個。雖然*可能*使用'IDENTITY'是更好的解決方案。 – 2013-03-25 05:38:11

+0

我認爲有一個稱爲ReReadable的隔離級別。我必須檢查MSDN,但我認爲身份列會更好 – Greg 2013-03-25 06:09:15

+0

@Greg:只需在我的答案中單擊鏈接到「事務隔離級別」,即可查看可用的級別。你是對的,一個身份專欄會更好,但已經有2個其他答案暗示了這一點。此外,身份列僅適用於列爲整數*和*時,您可以控制架構*和*您不必將列設置爲特定值。 – Gabe 2013-03-25 12:18:52