2011-09-26 47 views
1

我在最後一個線程中同時提出了兩個問題,第一個問題已得到解答。我決定將原始線程標記爲已回答,並在此重新發布第二個問題。鏈接到原始線程,如果有人想要它: Handling SQL Server concurrency issuesSQL Server併發

假設我有一個表中持有第二張表的外鍵的字段。第一個表中的記錄最初沒有相應的記錄,因此我在該字段中存儲NULL。現在,用戶在某個時候運行一個操作,該操作將在第二個表中生成一條記錄,並將第一個錶鏈接到該記錄。如果兩個用戶同時嘗試生成記錄,則應創建並鏈接單個記錄,另一個用戶將收到一條消息,指出該記錄已存在。我如何確保在併發環境中不創建重複項?

我需要執行的步驟如下:

1)查找的在表中的記錄x個甲

2)執行,其準備被插入到表B中

單行一些業務邏輯

3)更新在步驟1中選擇的記錄),以指向新生成的記錄在表B中

我可以使用SCOPE_IDENTITY()來檢索新創建的記錄的表B中的主鍵,所以就不會不需要擔心新的問題記錄因同時交易而丟失。不過,我需要消除併發執行進程的可能性,從而導致創建表B中的重複記錄。

+0

您是否想阻止後續連接實現(1)和(2a(業務邏輯)),或者只是忽略(2b(插入行))的冗餘計算? –

+0

我需要避免在表B中創建副本,或者至少檢測副本並通過回滾事務來清除副本。 B不具有A的鍵,因爲從A到B的關係可以是多對一。 – Trent

回答

3

在SQL Server 2008中,這可以通過過濾唯一索引來處理:

CREATE UNIQUE INDEX ix_MyIndexName ON MyTable (FKField) WHERE FkField IS NOT NULL 

這將要求所有非空值是唯一的,並且數據庫將執行它。

+1

+1,我正在打字! –

+1

@KM - 偉大的思想等等:) – JNK

+0

沒有讀過這個問題,但2005年過濾的索引不可用,需要一個索引視圖。 –

2

模擬獨特的過濾指標約束目的的2005年的辦法是

CREATE VIEW dbo.EnforceUnique 
WITH SCHEMABINDING 
AS 
SELECT FkField 
FROM dbo.TableB 
WHERE FkField IS NOT NULL 

GO 

CREATE UNIQUE CLUSTERED INDEX ix ON dbo.EnforceUnique(FkField) 

連接該更新基表需要有正確的SET選項,但除非你使用非默認的選項,這將是不管怎樣的情況下在SQL Server 2005(ARITH_ABORT曾經是一個問題,2000年)

2

使用計算列

ALTER TABLE MyTable ADD 
    OneNonNullOnly AS ISNULL(FkField, -PkField) 

CREATE UNIQUE INDEX ix_OneNullOnly ON MyTable (OneNonNullOnly); 

假設:

  • FkField是數字
  • 沒有FkField的衝突和-PkField值
0

決定去與以下幾點:

1)開始交易

2 )UPDATE tableA SET foreignKey = -1 OUTPUT inserted.id INTO #tempTable FROM (business logic) WHERE foreignKey is null

3)If @@rowcount > 0 Then

3a)在表2中創建記錄。

3B)使用捕捉新創建的記錄的ID scope_identity()

3C)UPDATE tableA set foreignKey = IdOfNewRecord FROM tableA INNER JOIN @tempTable ON tableA.id = tempTable.id

因爲我寫的垃圾到在步驟2中的外鍵字段),這些行被鎖定,沒有併發事務會觸及他們。第一筆交易可以自由創建記錄。事務提交後,被阻止的事務將執行更新查詢,但由於WHERE子句只考慮NULL foreignKey字段,因此不會捕獲任何原始行。如果沒有行返回(@@rowcount = 0),則當前事務退出而不在表B中創建記錄,並向客戶端返回某種錯誤消息。 (例如:Error: Record already exists