2008-10-03 78 views
1

團隊成員遇到了舊的內部系統問題,用戶雙擊網頁上的鏈接可能會導致從瀏覽器發送兩個請求,導致兩個數據庫插入同一記錄競賽狀況;最後一個運行失敗,主鍵違規。幾種解決方案和黑客已經提出和討論:雙擊雙插入分辨率?

  1. 使用JavaScript的網頁上通過禁止在第一次點擊的鏈接,以減輕第二次點擊。這是減少問題發生的快捷方式,但不能完全消除問題。

  2. 將請求執行包裝在事務服務器端。由於服務器負載和桌面上的鎖定級別,這被認爲是操作太昂貴。

  3. 捕獲由失敗的插入引發的主鍵異常,將其標識爲它,然後將其吃掉。這具有(a)供應商鎖定的缺點,必須知道數據庫特定異常的細微差別,以及(b)可能不記錄/處理合法的數據庫故障。

  4. 如果插入失敗,則嘗試更新記錄並檢查更新結果以確保返回1記錄受到影響,從而擴展#3。

其他選項還沒有被考慮?提出的選項有沒有被忽視的利弊?所有的罪惡中哪一個更小?

回答

1

您需要實現Synchronizer Token模式。

它是如何工作的:在服務器上爲每個請求生成一個值(令牌)。然後,您的表單提交中必須包含相同的標記。收到請求後,服務器令牌和客戶端令牌將進行比較,如果它們相同,則可以繼續添加您的記錄。然後重新生成服務器端令牌,以便包含舊令牌的後續請求將失敗。

關於中途下降有更詳細的解釋this page

我不確定你使用的是什麼技術,但是Struts爲這種模式提供了框架級的支持。見示例here

5

在隱藏字段的頁面上放置一個唯一標識符。只接受一個給定唯一標識符的響應。

+0

這增加了大量的開銷在服務器端 - 服務器的場中,他們將擁有所有必須知道這個標識符,他們會都同步和鎖定它,所以如果兩個請求在兩臺不同服務器之間保持平衡,那麼就沒有競爭條件。 – 2008-10-05 16:58:44

+0

如果唯一標識符是數據庫插入的主鍵,那麼您的數據庫完整性將負責處理它。 – 2008-10-06 01:05:33

0

看來你已經在那裏回答了你自己的問題; #1似乎是唯一可行的選擇。否則,你應該真的要做所有的三個步驟 - 數據完整性應該在數據庫級別處理,但是代碼中額外的檢查(例如顯式事務)以避免往返數據庫往往會對性能有好處。

2

這聽起來像你可能會濫用GET請求來修改服務器狀態(儘管情況並非如此)。雖然它可能不適合你的情況,但應該說明你應該考慮將鏈接轉換成POST表單。

0

REF您需要實現Synchronizer Token模式。

這是Javascript/HTML而不是Java