答案轉載地址:https://segmentfault.com/q/1010000003938997/a-1020000003975492
Oren Eini(又名 Ayende Rahien)建議開發者盡量避免數據庫的軟刪除操作,讀者可能因此認為硬刪除是合理的選擇。作為對 Ayende 文章的回應,Udi Dahan 強烈建議完全避免數據刪除。
所謂軟刪除主張在表中增加一個 IsDeleted 列以保持數據完整。如果某一行設置了IsDeleted標志列,那么這一行就被認為是已刪除的。Ayende 覺得這種方法“簡單、容易理解、容易實現、容易溝通”,但“往往是錯的”。問題在於:
刪除一行或一個實體幾乎總不是簡單的事件。它不僅影響模型中的數據,還會影響模型的外觀。所以我們才要有外鍵去確保不會出現“訂單行”沒有對應的父“訂單”的情況。而這個例子只能算是最簡單的情況。……
當采用軟刪除的時候,不管我們是否情願,都很容易出現數據受損,比如誰都不在意的一個小調整,就可能使“客戶”的“最新訂單”指向一條已經軟刪除的訂單。
如果開發者接到的要求就是從數據庫中刪除數據,要是不建議用軟刪除,那就只能硬刪除了。為了保證數據一致性,開發者除了刪除直接有關的數據行,還應該級聯地刪除相關數據。可Udi
Dahan提醒讀者注意,真實的世界並不是級聯的:
假設市場部決定從商品目錄中刪除一樣商品,那是不是說所有包含了該商品的舊訂單都要一並消失?再級聯下去,這些訂單對應的所有發票是不是也該刪除?這么一步步刪下去,我們公司的損益報表是不是應該重做了?
沒天理了。
問題似乎出在對“刪除”這詞的解讀上。Dahan 給出了這樣的例子:
我說的“刪除”其實是指這產品“停售”了。我們以后不再賣這種產品,清掉庫存以后不再進貨。以后顧客搜索商品或者翻閱目錄的時候不會再看見這種商品,但管倉庫的人暫時還得繼續管理它們。“刪除”是個貪方便的說法。
他接着舉了一些站在用戶角度的正確解讀:
訂單不是被刪除的,是被“取消”的。訂單取消得太晚,還會產生花費。
員工不是被刪除的,是被“解雇”的(也可能是退休了)。還有相應的補償金要處理。
職位不是被刪除的,是被“填補”的(或者招聘申請被撤回)。
在上面這些例子中,我們的着眼點應該放在用戶希望完成的任務上,而非發生在某個
實體身上的技術動作。幾乎在所有的情況下,需要考慮的實體總不止一個。
為了代替 IsDeleted 標志,Dahan 建議用一個代表相關數據狀態的字段:有效、停用、取消、棄置等等。用戶可以借助這樣一個狀態字段回顧過去的數據,作為決策的依據。
刪除數據除了破壞數據一致性,還有其它負面的后果。Dahan建議把所有數據都留在數據庫里:“別刪除。就是別刪除。”
這個答案下面有一條評論,我覺得很有道理
根據我自己的實際操作經驗來看的話,首先是要有個狀態字段,用以標示該條記錄是否還有效,正常的業務邏輯都只是通過修改這個狀態字段來實現,絕對不能有DELETE語句出現在業務邏輯中。
但同時,我又對每個關系都設置了級聯刪除的屬性,這是因為測試時難免會產生大量的垃圾數據,長此以往會造成整個數據庫很臟,因此為了便於清理起見,還是會定期親自操作刪除這些垃圾數據
最近在開發Essay的新版本,在設計數據庫時遇到了這個問題,在刪除一篇文章時,是否應該從數據庫中刪除?如果刪除,它下面的關聯評論咋辦?關聯標簽的咋辦?同樣的問題還出現在評論回復上,如果原評論已刪除,那回復的評論是否一並刪除?
最后細想了一下,比較好的做法是軟硬刪除方式都有,這有點像垃圾箱功能,放到垃圾箱是軟刪除,清空垃圾箱是硬刪除。
最后說一下,我在Essay的新版本上投入了大量的時間,整個項目重寫了(這就是為什么github一直未更新的原因),但技術選型沒有變。它也不再是一個玩具項目,而是根據工作中的實際經驗,開發的一個可用於線上的博客系統,一個完全基於JavaScript開發的同構應用。感興趣的可以watch下,很快他將會與大家見面