問題如下:
不論是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的問題,之後我會再寫編文和大家分享。
我曾經天真的以為,識得用db的transaction, read committed, uncommited, commit, rollback係好簡單 係programmer 都識的基本 。 後來才發現原來真的會的人少之又少
回覆刪除Transaction commit同rollback係一樣基本o野,
回覆刪除莫講讀CS的人,連IVE都有教 :clown:
但Set SQL Server transaction isolation level 又係另一樣o野。
但因為SQL Server default level已經係READ COMMITTED, 而呢個case前後相差10分鐘, 就算set更嚴格的SERIALIZABLE 同REPEATABLE READ都無補於事。
所以我不認為修改Session level的isolation就可以解決問題。
所以如果答interviewer用transaction死硬,因為單單用Transaction係解決唔到呢個問題,因為就算拉近到1,2秒之間的事,後者最多只係在Quene狀態。
問題在於第二個人有可能唔知情情況下over write,要commit定rollback其實已經同呢個case冇關。
如果第二個人不知情,資料正確,什麼去決定佢不能Commit而應該RollBack?
自從 NoSQL, BigTable, Denormalize 出現之後, db的transaction唔一定係最好的方法.
回覆刪除想想 SVN 同 Git 的分別可以知了.
有無教係一回事, 但係識唔識"應用" 又係另一回事
回覆刪除甚至我見過有人以為 atomic action 唔用transacion唔會出事
---
其實無 deadlock 方法真係有好多.
WinForm 可以用 dual connection, addition lock table, update with commit 加上 read uncommited 去做 locking
而 WebForm, 可以用 lock table + expiry time 去做 locking (可配合 read uncommitted 去 update lock table)
而 record version, 好多DB都有 timestamp/row_version 功能
1分鐘定10分鐘其實無分別
你個問題是關於Concurrent update,同deadlock是兩回事,亂答用transaction的人其實概念未清
回覆刪除