2010-11-15 36 views
3

我是一個業餘愛好者程序員,但一直在做這件事。我正在編寫一個小型文檔管理應用程序以供在工作中使用(在C#中)。當用戶打開一條記錄時,我會更新它以表明它當前被鎖定以進行編輯。如何在記錄鎖定時安全地退出DBMS?

我不知道的是如何確保應用程序退出時不安全的數據庫被更新的內容(如:電腦關機意外)?另外,當應用程序通過被用戶關閉的計算機退出時,我應該如何更新它?我只想確保在沒有人查看記錄時記錄被標記爲鎖定。

回答

2

以下是SQL Server的正常工作方式。開發者發佈的「記錄鎖」與客戶端 - 服務器體系結構無關。您將共享文件架構與客戶端 - 服務器架構混淆在一起。

確保表中有一個時間戳列(由數據庫引擎自動更新)。

閱讀您要編輯的行。將行中的時間戳放入變量中。

更新語句如下所示:

update myTable 
set col = {some value} 
where id = {your id} 
AND 
timestampcolumn = {the timestamp the row had when you read it in} 

如果因爲你讀它的人已經改變了該行,就會有不同的時間戳和沒有記錄匹配您的WHERE子句條件,所以你的更新將失敗。然後您可以決定要做什麼。

當您使用SQL-Server(或Oracle或任何真正的客戶端 - 服務器架構)時,您可以在客戶端PC上拔下插頭,而不會對服務器造成任何負面影響。

+0

PS如果你想要谷歌的話,這叫做「樂觀鎖定」。 – Polyfun 2010-11-15 12:08:03

+0

樂觀併發是一回事,但有*真實場景,需要在記錄級別公佈和追蹤「鎖定」(注意:不是RDMBS鎖定)*。另外,IIRC「rowversion」現在通過「timestamp」引用(儘管在SQL服務器中它們是同義詞) – 2010-11-15 12:09:48

+0

@ShellShock - 它是樂觀的*併發性* - 那裏*沒有任何「鎖定」。 – 2010-11-15 12:10:30

1

在C#中,您可以使用try-catch-finally塊,並在finally中進行整理。 (不管什麼都應該執行)。

你可以通過創建一個類實現IDisposable,它得到了鎖,並釋放它時,處置方法被調用達到同樣的事情。然後,每當你消耗的是類(獲得鎖),放在一個用塊

using (RecordLockingThing myThing = new RecordLockingThing()) 
{ 
    //DoStuff 
} 
//Now myThing is out of scope, and will have been disposed. 

只要確保你的RecordLockingThing正確,安全地釋放,在上述配置方法的鎖。

另一種策略可能是沒有標誌的記錄打開時鎖定他們,但作爲編輯,而不是對其進行標記(或遞增版本號)。然後你可以允許多人打開記錄。當有人提交編輯時,讓他們提交修訂編號,如果匹配,提交編輯並增加修訂,如果不是,則報告「空中相撞」,並丟棄編輯(不是非常友好),或嘗試並讓用戶合併記錄。

如果編輯與讀取相比非常少見,第二個策略在實踐中將更加有用,因爲您絕不會阻止用戶至少查看記錄,並且不存在孤立鎖的風險。

0

要處理意外關閉的問題,我通常會給每個邏輯鎖定過期;這可能意味着(例如)您需要LockOwnerIdLockExpiry列,但這通常不是問題。如果用戶仍在屏幕中,您的應用始終可以延長,但這意味着如果機器只是從網絡中斷開,則記錄將在幾分鐘內隱式出現。另一種選擇是允許關鍵用戶粉碎鎖。

重新用戶終止的應用程序;只是跟蹤你有什麼鎖,並刪除它們; p

0

我有一個DMS應用程序類似的問題,在服務器端我使用會話對象,活動用戶的集合,每個客戶端更新會話對象每5分鐘。因此,如果某行被鎖定,並且鎖定該行的用戶不再處於會話對象中,那麼我將其釋放。爲了解鎖,我在服務器端運行後臺線程,每分鐘掃描一次鎖定的行。

0

我很驚訝,似乎沒有人提到sp_getapplock,它是親屬。如果您保持單個連接對服務器開放(並且鎖由Session擁有,而不是Transaction),則鎖將保持不變。如果連接中斷(例如客戶端計算機已崩潰),則與SQL Server中的所有內部鎖一樣,鎖將被釋放。

實質上,它是讓SQL Server使用它在內部用於應用程序的相同鎖定機制的一種方法。

正如我所說的,一個小問題是,你必須保持連接到服務器打開。因此,對於多達50個客戶而言,或許更適合,而不是如果你有1000個客戶參與。我還要補充另一個警告 - 我沒有使用這些設施建立生產系統。