2013-08-30 48 views
0

我們正在構建一個ajax應用程序。我們希望有幾個用戶可以同時訪問該應用程序。因此,我有這樣的想法:以一種方式運行每個更新查詢,以便它們提供以前的字段值。問題是,如果以前的值不是系統預期的那麼PostgreSQL應該拋出一個錯誤(也就是說有人在我們的用戶被賦予值後修改了它)。在一個事務和數據庫級別處理這個問題是很好用的,因爲沒有併發問題。這可能嗎?處理數據庫中的AJAX併發問題

回答

2

因此,我有一個辦法運行的每一個更新查詢的想法,讓他們提供字段的前值

你所描述稱爲「樂觀併發控制」或一招「樂觀鎖定「。它已經建立並已被證實。

參見:

即使ODBC早在今年點這樣做,雖然ODBC使用的原始方法有一些問題。

擁有一個專用修訂列通常要好得多,它應該是一個隨每次更新而遞增的整數。不要使用時間戳。

你可以這樣做:

SELECT col1, version FROM sometable WHERE id = 42; 

想象你得到的結果行('bob',7)你然後運行:

UPDATE sometable SET col1 = 'fred' WHERE id = 42 AND version = 7; 

,並檢查有多少行受到了影響。如果它爲零,則知道存在更新衝突。

如果您在同一數據庫中混合使用樂觀鎖定和常規應用程序,則可以使用a trigger to make sure the optimistic locking column always gets incremented,以便您的常規應用程序和操作鎖定應用程序可以良好地協同工作。

這種策略不能在PostgreSQL的觸發分區表上工作

1

如果你想在數據庫中這樣做,我想你將不得不在表上使用觸發器。在觸發器中,您可以根據「新」(您發送的更新內容)來檢查「舊」(表中的內容)。我不認爲你可以使用這個規則。您也可以使用表中最後一次修改的列,而不是傳遞和比較所有列。

CREATE TRIGGER check_update 
    BEFORE UPDATE ON table 
    FOR EACH ROW 
    WHEN (OLD.timestamp IS DISTINCT FROM NEW.timestamp) 
    EXECUTE PROCEDURE check_update(); 

如果您不想使用時間戳,則可以在WHEN子句中包含所有列檢查。然後您可以讓check_update()過程執行某些操作,也許會引發異常或返回現在存在的數據。可能有更好的方法,但這應該起作用。

0

postgreSQL MVCC模型可以確保在用戶事務讀取並保存數據更改時,沒有人正在更改數據。這將特別通過使用serializable transaction level ... 但是來執行。

你真正的問題不在於保存階段,在這個階段很容易打開一個事務,讀取數據,修改它並提交這個事務;你的問題是網絡問題。 您無法打開一個事務,讀取數據,通過您的Web應用程序將其推送給最終用戶,然後等待幾秒/分鐘的時間用於ajax請求,然後保存更改的數據並提交。交易不會長時間保持開放狀態,並會在用戶發佈後恢復。

因此,在Web應用程序服務器端,您擁有的是表單文章,並且您想要保存更改的數據。您特別想要檢測在用戶加載頁面,進行某些操作並決定按下提交按鈕之間會發生變化的數據。一種方法是在用戶信息中存儲原始未改變數據的副本,並將此數據與當前存儲數據進行比較。另一種方法是使用@Scott S的解決方案(最後一個修改時間戳)來標記數據庫中的數據記錄。並在每次修改後重新計算(可能使用觸發器)。然後,將這些(或這些)數據簽名嵌入到用戶表單中,並在打開保存事務之後,首先要做的就是比較md5sum,並在數據似乎已被更改的情況下回滾整個操作。因爲數據庫將僅管理異步數據操作(事務隔離管理和鎖定)而不是長期用戶共享數據策略,這不是數據庫角色,而是應用程序邏輯。您的應用程序必須通過異步窗體lobd和posts來處理共享策略。例如參見維基百科處理它的方式。如果您在編輯模式下從多個位置加載相同的頁面並嘗試同時保存,則會檢測到之前的修改並且您的第二次保存被拒絕。對於絕大多數Web應用程序igores來說,這是個棘手的問題,最後的提交也是贏得的。

UPDATE

要使用同步修改的AJAX管理走得更遠,你可以建立一個相當複雜的系統,用LISTENNOTIFY SQL關鍵字檢測修改和推背論文在客戶端事情。如果您的應用程序服務器是持久性的(不像PHP或jsp),並且如果您使用與comet或其他push technology等系統一起使用持久性ajax連接仿真,那麼當另一個用戶進行事務提交改變了某些數據以他的形式顯示。這不會消除用戶在非常近的時間提交修改的問題(並行用戶請求處理服務器端)。對於最後一種情況,唯一的解決方案是使用一個很好的交易,也許在可序列化的槓桿中,並且總是管理用戶修改可能被拒絕的事實服務器端(這是交易的關鍵,總是管理交易可以即使您沒有犯錯誤,也僅僅因爲修改與並行提交事務衝突而被服務器回滾)。

+0

使用'LISTEN'和'NOTIFY'來提醒用戶衝突是很有用的。其餘的方式過於複雜,但;只需使用修訂版計數器列即可,它很簡單,可靠且易於執行。 –

+0

@Craig Ringer:如果你只是在兩個並行事務中增加它,甚至修改計數器可能會被嚴重管理,所以在大多數事務模式下,你應該讀/檢查事務中的版本,並確保正確的行鎖定和/或事務中止。 – regilero