2010-06-24 40 views
3

我有一個基本上充當文件索引的MySQL表。每條記錄的主鍵也是我的虛擬主機上目錄中文件的名稱。文件+數據庫事務安全

當用戶想從系統中刪除一個文件,我要保證某種交易的安全性,即如果在刪除記錄不會被刪除的文件出現錯誤,如果由於某種原因,數據庫服務器死機該文件將不會被刪除。無論發生什麼事情都不太可能發生,但如果出現問題的可能性很小,我想阻止它發生。

不幸的是我絕對不知道如何實現這一點。我是否需要計算出哪些不太可能失敗,並簡單地假設它永遠不會?有沒有已知的最佳做法?

哦,這裏是踢球者 - 我的虛擬主機只支持MyISAM表,所以沒有MySQL交易給我。

萬一它很重要,我使用PHP作爲我的服務器端腳本語言。

回答

3

無論文件是通過UPDATE還是刪除行從數據庫中「刪除」,問題都是一樣的 - 數據庫+文件操作不是原子操作。 UPDATE或DELETE都比另一個更安全,它們都是數據庫中的事務,而文件操作不是。

解決方案是從來沒有任何衝突的數據狀態。只有一個來源被認爲是「真相」,另一個來源則反映了這個真相。這樣,如果兩者之間存在矛盾,你就知道「真相」是什麼。事實上,永遠不會有「邏輯」的不一致性,只有磁盤上的物理文物纔會表現出善後。

在大多數情況下,數據庫是The Truth的更好表示。

這裏的真值表:

File Exists -- DB Record exists -- Truth 
    Yes    No    File does not exist 
    Yes    Yes   File does exist 
    No    Yes   File does exist, but its in error. 
    No    No    File does not exist 

操作上,這裏是如何工作的。

要創建文件,請將文件複製到最終目的地,然後在數據庫中輸入條目。

如果文件複製失敗,則不更新數據庫。 如果文件複製成功,但數據庫未更新,則文件「不存在」,因此回到第一步。 如果文件複製成功並且數據庫更新成功,則所有內容均爲A-確定

要刪除文件,首先更新數據庫以顯示文件被刪除。 如果數據庫更新成功,則刪除實際的文件。 如果數據庫更新沒有,則不要刪除該文件。 如果文件刪除失敗,沒有問題 - 文件仍然被「刪除」,因爲數據庫是這樣說的。

如果您按照工作流程進行操作,那麼在數據庫表示它存在時文件應該丟失是「無法」的。如果文件丟失,您有未定義的狀態,您需要解決。但是這不應該發生,除非有人在你的文件系統上行走。

數據庫事務有助於保持誠實。

有時候,正如Jonathan所說,你應該運行某種清理,同步過程以確保沒有任何流氓文件。但即使如此,除了文件空間,這實際上不是問題,特別是如果實際文件的文件名與原始文件名無關。 (即他們是合成文件名)這樣你就不必擔心覆蓋等。

+0

文件名是從表中的主鍵生成的,專門用於防止衝突。感謝真相表 - 它讓我從不同角度考慮問題總是有幫助的。 – robinjam 2010-06-24 06:38:35

+0

順便說一下,我認爲MySQL保證單個操作(如UPDATE和DELETE)的事務安全性,即它可以工作或返回錯誤。我錯了嗎? – robinjam 2010-06-24 06:43:00

+0

不,你是對的。這就是如何工作的原因,因爲你總是「知道」數據庫的狀態(因爲即使失敗它也會回滾),所以它是一個更可靠的「真相源」。我只是指出更新和刪除之間沒有區別 - 它們作爲記錄文件狀態的手段同樣安全,而且由於數據庫的事務性質,這也是如此。 – 2010-06-24 14:22:31

3

在這種情況下,我認爲我會使用邏輯刪除機制,即使記錄仍然存在於數據庫中,並且文件仍然存在於文件系統中,記錄被標記爲已刪除。我可能會在文件被邏輯刪除時將文件移動到新的位置(認爲'回收站'),並使用新位置以及'邏輯刪除'標記更新記錄。

然後,稍後,您可以執行脫機清除操作以物理刪除標記爲邏輯刪除的文件和記錄。

這降低了實時數據的風險。它的SQL略微複雜,但鑑於可能的工作 - 重命名主表,然後創建具有相同名稱的視圖作爲主表曾經有過,但與消除邏輯上刪除的記錄標準:

CREATE VIEW MainTable(...) AS 
    SELECT * FROM RenamedTable WHERE DeleteFlag = 'N'; 

即使升級到提供MySQL事務的公司並不是一個巨大的幫助。您需要一個可以在文件系統和DBMS之間運行兩階段提交協議的事務管理器,這是非常重要的。

+0

非常好的建議。我期待着在我之前進行更多的重構工作! – robinjam 2010-06-24 06:39:10

2

您可以在File表中創建具有兩個值的狀態列(或「is_active」列):0 =激活,1 =已刪除。

  • 當用戶刪除文件時,只有狀態字段被更改,文件保持不變。
  • 當用戶瀏覽文件時,只顯示Status = 0的文件。
  • 管理員可以查看/刪除Status = 1的文件。