MS Access (MDB) 並發
對於一個小型項目,我需要使用一個要求非常輕的簡單數據庫:很少的表,總共不超過幾千條記錄,2 或 3 個使用者。我在.NET 環境中工作。
由於數據庫伺服器(即使是那些 Express 版本)在這種情況下似乎是一個巨大的矯枉過正,一個非常簡單的 MDB 數據庫可以滿足大多數要求。但是,我擔心並發性。我的想法是將 .mdb 文件放在網路共享上,讓使用者從基於 .NET 的客戶端訪問該文件。數據庫主要針對只讀操作,但使用者有時也需要更新/刪除記錄。如果當時無法做到這一點(由於數據庫被鎖定或其他原因),我可以在客戶端上保存更新並在以後處理它們。
問題本身涉及以下幾點:
- MDB 中如何處理並發讀取?
- MDB 中如何處理並發更新/刪除?
- 是否有鎖的概念以及如何在 .NET 應用程序中利用它?
- 將 MDB 文件放在網路共享上是好主意還是壞主意?
當我在 .NET 中工作時,我也很想知道如何檢測任何並發問題並採取適當的措施。即,我應該擷取哪個異常以及您建議採取什麼行動?
編輯:這可能是我對問題的錯誤描述,但大多數答案似乎都建議使用完整的數據庫伺服器。我確實了解安裝伺服器的區別和好處,並且實際上已經在 MSSQL 和 Oracle 上實施了相當數量的項目。但是,在這個問題中,我只關心 Access 及其並發問題,所以請不要建議使用數據庫伺服器。
謝謝你的幫助。
這是一個古老的問題,但沒有人真正回答過它。以下是問題:
- MDB 中如何處理並發讀取?
- MDB 中如何處理並發更新/刪除?
- 是否有鎖的概念以及如何在 .NET 應用程序中利用它?
- 將 MDB 文件放在網路共享上是好主意還是壞主意?
前兩個問題基本上可以用一個解釋來回答。這裡有一個關鍵警告:我在這裡給出的答案是針對 Jet MDB(及其變體)的,並不完全適用於從 A2007 開始引入的新文件格式,即 ACCDB 格式。我還沒有完全探討從 ACE 中移除 Jet ULS 的影響,下面的一些評論可能會假設 Jet ULS 在引擎蓋下。但是,對於很多事情,您可以將“LACCDB 文件”替換為“LDB 文件”,結果將是相同的。
1-2) 並發讀取/更新/刪除
Jet 數據庫引擎通常被稱為“文件伺服器”數據庫,因為沒有伺服器端惡魔管理伺服器上的數據文件的 I/O。這意味著所有使用 Jet MDB 的客戶端都在直接讀取文件。
如果沒有內置某種機制來處理對文件的並發訪問,那當然是災難的根源。
Jet 使用記錄鎖定文件,如果您的 MDB 是“MyFile.MDB”,則記錄鎖定文件將位於同一文件夾中並稱為“MyFile.LDB”。LDB 文件記錄了哪些 Jet ULS 使用者打開了 MDB 文件、該使用者從哪個工作站連接,以及協商並發問題所需的所有資訊。
現在,對於那些開始研究客戶端/伺服器數據庫引擎的人來說,這可能看起來很原始和危險,但是在開發 Jet 數據庫引擎時,它的目的是用作小型工作組的桌面數據庫引擎,並且它與 xBase 和 Paradox 等其他桌面數據庫引擎競爭,它們都使用類似的鎖定文件來管理來自多個客戶端的數據文件的並發使用。
在 Jet 數據庫文件中,鎖定應用於數據頁(在 Jet 4 中增加到 4K,而在 Jet 3.x 和之前的版本中,它們是 2K),或者如果數據表最初創建為使用記錄級鎖定。在 Jet 4 的早期,許多人發現記錄級鎖定非常緩慢,尤其是在使用悲觀鎖定時,因此許多 Access 開發人員除了頁面級鎖定之外從未使用過任何東西(@David Fenton 舉手!)。
事實上,當使用樂觀鎖時,您可以避免悲觀鎖帶來的大部分並發問題。
一些警告:
- 從 DAO 中,記錄級鎖定不可用,並且您只能獲得頁面級鎖定。
- 從 DAO 中,有許多用於控制樂觀/悲觀鎖定的選項,特別是 OpenRecordset 方法的 LockEdits 參數,但它也與 OpenRecordset 選項參數中指定的某些設置互動(例如,選項 dbReadOnly 不能與鎖定編輯)。除了鎖定之外,還有一致/不一致更新的選項,所有這些都可以與事務互動(例如,未送出事務中的更改不會對其他使用者可見,因此不會與他們發生衝突,但它可以在所涉及的表上放置只讀鎖)。
從 ADO/OLEDB 中,這些 Jet 並發控制結構將映射到 ADO/OLEDB 中的相關函式和參數。由於我僅從 Access 使用 Jet,因此我僅通過 DAO 與其互動,因此我無法建議您如何使用 ADO/OLEDB 控制這些,但關鍵是 Jet 數據庫引擎在訪問它時提供對記錄鎖定的控制以程式方式(而不是通過 Access UI)——它只是更複雜。
3) 鎖和.NET
除了您可能會使用 OLEDB 作為數據介面之外,我在這裡無法提供任何建議,但關鍵是 db 引擎本身就存在鎖定功能/控制項,因此可能有一種方法可以通過OLEDB。不過,它可能並不漂亮,因為在我看來 OLEDB 是圍繞客戶端/伺服器架構設計的,而 Jet 的基於文件的鎖定可能無法以優雅的方式映射到它。
4) 網路共享上的 MDB
Jet 對任何網路連接中最輕微的故障都非常敏感。因此,低頻寬網路會增加通過慢速連接打開的 Jet 數據庫的脆弱性。
這是因為數據庫文件的主要塊必須通過線路拉到本地電腦的 RAM 進行處理。現在,許多人錯誤地聲稱整個 MDB 文件是通過網路傳輸的,或者整個表都是通過網路傳輸的。這不是真的。相反,Jet 首先請求索引(並且請求不超過完成查詢所必需的),然後根據該結果確定需要哪些數據頁面,然後僅提取這些頁面。這是令人驚訝的高效和快速。
此外,Jet 進行了一些非常智能的記憶體,這可能意味著第一個數據請求可能需要一段時間,但由於記憶體,後續對相同數據的請求幾乎是即時發生的。
現在,如果你沒有很好地索引你的表,你最終可能會拉出整個表並進行全表掃描。同樣,如果您基於不屬於 Jet 的 SQL 方言的客戶端函式的標準,您最終可能會拉取一個完整的表(排序,例如,Replace(MyField, “A”, “Z”) 可能會導致全表掃描)。但是這種事情對於客戶端/伺服器架構也將是低效的,因此正確索引事物並小心使用 UDF 或非 Jet 兼容函式只是常識模式設計。一般來說,對於客戶端/伺服器有效的相同操作將在 Jet 中有效(主要區別在於,對於 Jet,您最好使用持久連接,以避免重新創建 LDB 文件的成本,這很重要)。
要避免的另一件事是嘗試通過 WiFi 連接使用 Jet 數據。我們都知道 WiFi 有多不可靠,它只是在嘗試通過 WiFi 連接處理 Jet 數據時遇到麻煩。
底線:
如果您使用 MDB 作為數據儲存來提供來自 Web 伺服器的數據,則應將數據盡可能靠近 Web 伺服器的 RAM。這意味著在可能的情況下,在連接到物理 Web 伺服器的磁碟捲上。如果這是不可能的,您需要快速、可靠的 LAN 連接。如今,數據中心中的 GB LAN 非常普遍,我很樂意通過這種連接處理 Jet 數據。
對於共享使用,例如,執行 VB.NET 桌面應用程序的多個客戶端工作站共享單個 Jet MDB 作為數據儲存,將數據文件放在可靠的文件伺服器上是非常安全的。在可能的情況下,最好將 Jet MDB 文件放在不具備多種用途的機器上(例如,執行 Exchange、SQL Server 並充當文件伺服器和列印伺服器的域控制器可能不是最佳位置) . 像 Exchange 這樣的應用程序會嚴重干擾文件伺服器的功能,我通常建議不要將 MDB 文件放在作為 Exchange 伺服器的多任務伺服器上,除非它的容量非常小。
其他注意事項:
- 切勿嘗試在複製的文件系統上分發 MDB,除非所有使用者都使用相同的副本。也就是說,如果您有兩台伺服器在它們之間複製文件,甚至不要考慮從兩台伺服器編輯 MDB 文件。這幾乎會立即損壞文件。
- 我建議不要將任何 MDB 儲存在通過本機 Microsoft SMB 網路提供服務的本機 Windows 文件系統以外的任何地方。這意味著沒有 Novell、沒有 Linux、沒有 SAMBA。造成這種情況的關鍵原因是 Jet 顯然在 Windows 文件系統中的某些低級鎖定功能中存在低級掛鉤,這些掛鉤並未 100% 複製到其他文件系統上。現在,我對此非常保守,許多稱職的 Access 開發人員報告了正確配置的 Novell 文件伺服器的出色結果(通常需要進行一些記錄鎖定調整,儘管這些天可能不太相關 - 我不’甚至不知道 Novell 是否還存在!),以及執行 SAMBA 的基於 Linux 的文件伺服器的出色性能。我對此持謹慎態度,並建議任何客戶端反對它(這包括各種 SAN 設備,
- 出於同樣的原因,我永遠不會在任何虛擬化文件系統上執行它們。但是,我有一個客戶,她多年來一直在 Mac Air 上的 Parallels 下執行她的單使用者 Access 應用程序,現在沒有出現任何問題。但它是單使用者的,所以鎖定問題相對較小。
我不知道這是否回答了你的問題。這一切都基於我作為 Access 開發人員 13 年來經常使用 Jet 以及對唯一出版的關於 Jet 的書籍《Jet Database Engine Programmers Guide》(僅適用於 Jet 3.5)的研究。我沒有提供任何真實的引用,但如果有人需要我所說的任何細節,我會盡可能地進行研究。