2012-09-19 80 views
12

我意識到,MongoDB本質上並不會支持這些類型的事務。但是,我發現我確實需要以一種有限的方式使用它們,所以我想出了以下解決方案,我想知道:是這樣做的最好方式,它可以改進當?(之前我去應用它在我的應用程序!)MongoDB中的多文檔'交易'

很顯然,交易是通過應用程序(在我的情況下,一個Python網絡應用程序)控制。對於在本次交易(任何集合)每個文檔,下面的字段添加:

'lock_status': bool (true = locked, false = unlocked), 
'data_old': dict (of any old values - current values really - that are being changed), 
'data_new': dict (of values replacing the old (current) values - should be an identical list to data_old), 
'change_complete': bool (true = the update to this specific document has occurred and was successful), 
'transaction_id': ObjectId of the parent transaction 

此外,還有一個transaction集存儲文件,詳細說明進度每一筆交易。他們看起來像:

{ 
    '_id': ObjectId, 
    'date_added': datetime, 
    'status': bool (true = all changes successful, false = in progress), 
    'collections': array of collection names involved in the transaction 
} 

而這裏是過程的邏輯。希望它能夠以這種方式工作,如果它被中斷或者以其他方式失敗,它可以被正確地回滾。

1:設置一個transaction文檔

2:對於每個由該事務受影響的文檔:

  • 設置lock_statustrue(到 '鎖定' 從作爲文件修改)
  • data_olddata_new設置爲其舊值和新值
  • 設置change_completefalse
  • 設置transaction_id到的ObjectId的transaction文件的,我們只是做

3:執行更新。對於每個受影響的文檔:

  • data_new值替換該文件中任何受影響的領域
  • 設置change_completetrue

4:transaction文檔的statustrue(所有數據已成功修改)

5:對於受交易影響的每個文檔,做一些清理:

  • 刪除data_olddata_new,因爲他們不再需要
  • 設置lock_statusfalse(解鎖文件)

6:取出transaction文件在步驟1中設置(或所建議的,將其標記爲已完成)


我認爲邏輯上是這樣工作的,如果它在任何時候都失敗了,所有的數據都可以回滾或者事務可以繼續(取決於你想要做什麼)。顯然所有的回滾/恢復/等。由應用程序執行,而不是數據庫,通過使用transaction文檔和其他集合中具有該transaction_id的文檔來執行。

這個邏輯中有沒有明顯的錯誤,我錯過了或忽略了?是否有更有效的方法來處理它(例如,從數據庫中寫入/讀取較少)?

回答

10

作爲一個通用的響應,MongoDB上的多文檔提交可以作爲兩階段提交執行,這在手冊中已經有所記載(請參閱:http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/)。

通過手動建議的模式是簡單地執行以下操作:

  • 設置一個單獨的transactions集合,其包括目標文檔源文檔狀態(的交易)
  • 創建新的交易對象initial作爲state
  • 開始進行交易,並更新statepending
  • 申請交易到兩個文件(目標,源)
  • 更新交易狀態committed
  • 使用發現,以確定文件是否反映交易狀態,如果正常,更新事務狀態done

另外:

  • 你需要手動處理的故障情況(如下所述事情都沒有發生)
  • 您需要手動執行回滾,基本上通過引入名字statecanceling

爲您實現一些具體注意事項:

  • 我會阻止您將lock_status,data_old,data_new等字段添加到源文件/目標文件中。這些應該是交易的屬性,而不是文件本身。
  • 要推廣目標/源文件的概念,我認爲你可以使用DBref S:http://www.mongodb.org/display/DOCS/Database+References
  • 我不喜歡刪除交易文件當他們完成的想法。將狀態設置爲done似乎是一個更好的主意,因爲這允許您稍後調試並找出已執行的事務類型。我相當肯定你不會用完磁盤空間(爲此也有解決方案)。
  • 在你的模型中,你如何保證一切都按預期發生了變化?你以某種方式檢查這些變化嗎?
+1

'DBrefs'建議很好。但是,這種兩階段提交方法是否可以與多個文檔一起工作(不會混亂?) - 在我的場景中,我需要同時更新一個集合中的一個文檔和另一個集合中的n個文檔(數量不盡相同)。 – johneth

+1

我想你也可以添加DBrefs的數組。 – jsalonen

+0

我會接受你的建議,而不是刪除交易文件。在文檔到文檔的基礎上,保證事情發生了預期的改變,這是通過使用'change_complete'字段完成的。 – johneth