2013-07-24 53 views
1

我在網絡上的數據庫上執行插入操作,並且我想確保我永遠不會嘗試插入已插入的數據。客戶端運行在Web瀏覽器中,使用Javascript將XMLHttpRequest發送到包含要插入數據的服務器。如果出現錯誤,我必須稍後再試 - 例如,可能存在暫時的網絡錯誤。但是,我不知道我可以保證我會通知插入成功,因爲在請求傳遞到服務器之後但在可以返回成功答覆之前,網絡可能會關閉。雖然這看起來對我來說不太可能,但是如果發生這種情況,將會完全搞亂數據庫,因爲無法知道某些條目不應該在那裏。如何確保我不會執行兩次相同的數據庫事務?

+0

您正在使用什麼數據庫管理系統? (PostgreSQL,MySQL,MS-SQL,Oracle,...?)而且 - 你是否熟悉主鍵,獨特的約束等? – ruakh

+0

你需要在db中做到這一點,而不是在網絡上 – dandavis

+0

是的,但是如何?插入的行基本上是一個字符串命令的日誌,並不要求它們是唯一的,唯一的要求是它們沒有被錯誤地複製(因爲否則當重播日誌時它將導致錯誤的結束狀態)。 – Michael

回答

1

使用是否存在要插入的數據,以便如果第二個相同的事務處理完畢,則簡單地忽略它。喜歡的東西:

INSERT MyTable (Value1, Value2, Value3) 
SELECT @Value1, @Value2, @Value3 
WHERE 
    NOT EXISTS (
     SELECT * 
     FROM dbo.MyTable T 
     WHERE 
      T.Value1 = @Value1 
      AND T.Value2 = @Value2 
    ) 
; 

請注意,這並不能完全解決潛在的競爭條件,其中兩個客戶端試圖執行在同一時間同一行動 - EXISTS子句中的時間執行INSERT操作之前,這可能會產生兩個試圖插入的客戶端。因此,您必須添加諸如WITH (UPDLOCK, HOLDLOCK)之類的鎖定(對於併發性非常糟糕,因爲如果該行不存在,它必須採取範圍鎖定來阻止無關的數據插入操作),或者在客戶機中適當地容忍有關重複鍵的錯誤。

如果它實際上是沒關係對於要,只要客戶端發送它複製的數據,那麼你就可以適應在幾個方面:

  1. 表中添加附加列,直到它是獨特的。

  2. 或者,創建作爲事務一部分的時間戳/序列號,插入後(在數據庫事務中)將此序列號記錄到表中。將插入與缺少此序列號相關聯。

開發一些策略,爲您的客戶持有發送請求,直到它們可以ACKED可能是一個附加的保護層,它同時可能會阻止一些重複的嘗試擺在首位 - 如果你沒有得到的現在確認,但稍後到達時,您確認/刪除排隊的已發送事務。

爲了將其推廣到防止重複DELETEUPDATE,您應該添加一個column of type rowversion。將此值包含在所有查詢的WHERE子句中,如果有人自上次讀取該行後觸摸了該行,那麼這些查詢將不會影響行。您仍然必須檢測到沒有行受到影響,之後才能做出明智的做法 - 這可能非常困難 - 但至少您已經檢測到並避免了編輯衝突或重複操作。

如果問題不能隔離到特定行的特定編輯,那麼請提出一個新問題,提供一些具體示例,以便您可以獲得更好的建議。給我一個帶有新問題鏈接的評論,我會看看。

+0

時間戳聽起來像是最好的解決方案,因爲事務中的其他事物可能都是相同的。 – Michael

+0

重訪這個問題...一般情況下,而不是簡單的插入有更新,下降等? – Michael

+0

請參閱更新。 – ErikE

0

嘗試添加一些約束你的領域:

ALTER TABLE Persons ADD CONSTRAINT MyTable UNIQUE (Value1, Value2, Value3) 
相關問題