問題如下:
不論是WinForms還是WebForms,假如有兩個使用者Tom 與 May,同時已經打開Edit Form,在修改同一個紀錄。
Tom正在埋頭苦幹更新紀錄,May卻慢條斯理工作。
Tom首先完成更新工作後,在12:10pm按下[Submit]按鈕,更新工序完成。
但與此同時,May還在更新,最後在12:20pm才完成工作,那當May按下[Submit]按鈕時,便會Overwrite Tom所更改的資料。
如何防止這個情況?
大家花幾分鐘,先想一想....
這個問題有幾個方向,我們要先決定 :
(1.) 是否容許讓多個使用者開啟同一個紀錄,並可以寫入資料庫?
(2.) 較遲的開啟者只能唯讀?
(3.) 完全防止其他人開啟同一個紀錄?
因為如果決定是(2)和(3)作解決方案的話,換句話說,在Tom進入時,我們已經要有一個Flag去讓May知道有其他人在更改資料中,再由Application 層面去決定如何提示和防止載入。
但很明顯沒有太多人會認為(2)和(3)的做法是最好,因為問題來自那一個Flag會產生DeadLock問題,先解釋一下為什麼 :
假設要做到(2)和(3)的話,可能大家會想到以下做法 :
1. 在SQL Table中加入一個Column - 叫[Locked], DataType Bit, Default 0。
2. 當Tom 進入時執行: Update MyContent Set Locked=1 Where id=@id
3. 當May 開啟紀錄前,會檢查[Locked]是否等於1,是的話,就不能更改或進入。
4. 當Tom更新完成後,把Locked設回0。
但問題就來了,假如Tom的電腦Hang機或Reboot,那一個紀錄就永遠是Locked=1,其他人亦不能修改,需要由Admin把Locked設回0。
那好了,說了那麼多,那應該怎麼做?
不知道大家有沒有接觸一些Version Control 或者Source System , 例如SVN,每次Commit一個檔案,都會有一個Revision流水號。
參考SVN的原理,我會把那一個Flag Column刪除,加入以下Column
ADD VersionNumber INT; ADD Modifier Int; /*(記錄StaffID)*/ ADD ModifyDate DATETIME;
在軟件層面上加入一個Version Checking方法,
不論你是WinForms或者WebForms使用Timer或者SetTimeOut + Ajax都是一樣。
程序大約如下:
1. Tom和May都可以同時進入Edit Form修改紀錄,兩個人得到的VersionNumber都是1。
2. 當Tom按下Submit時,會Update VersionNumber/Modifier/ModifyDate,假設是VersionNumber=VersionNumber + 1。
3. 當May之後按下Submit時,會進行一個Version Checking,因為Tom已經把VersionNumber轉變為 2,所以May會被提醒Version不同,這時候可以在讓May選擇覆寫? 檢視更新版本? 還是取消修改?
4. 在軟件層面中用Timer加上剛剛說的Version Checking,即使在編輯途中,也可以知道文件已變更。
以上就是我個人推薦的解決方面,沒有複雜的技術,但這可以解決到多人執行的問題,即使是三個,四個,五個人都可以應付到。
因為他們都可以有選擇權去繼續還是取消。
但當然我不得不承認,這還有很多解決方法。
再假設一個比較不真實的例子:
假如在同時同分同秒同微秒去執行讀寫Query的話,那會怎樣呢?
例如:
一部出單系統的過程是: (當然這是簡單虛構的Flow以容易理解)
1. 輸入Product ID查詢是否有貨
2. 有貨的話,提出貨品,並扣減數量
(1)和(2)之間沒有選擇,是連續性進行。
貨倉只剩下最後一部iPhone,有兩個Sales (Tom 和 May),同時想賣iPhone給客人,假設我虛構成是同一刻進行的話,兩者同時輸入ProductID,按下確定,會怎麼樣?
雖然大家都覺得這種在同一微秒的交互執行是幾乎沒有可能,但既然Programming是對錯誤零容忍的話,就深入看一看究竟。
而上述問題,已經變成SQL Server的Transaction Isolation Level 和 Lock的問題,之後我會再寫編文和大家分享。