-
概述
數據訪問層負責與數據庫存儲設備打交道,為業務層提供數據服務。
一般來說,dal包含了對數據的增、刪、改、查四種類型的操作,同時也包含着事務的管理、數據並發處理、查詢解析機制等相關邏輯。
-
數據訪問層設計策略
2.1倉儲模式
Repsoitory協調領域和數據映射層,起到了類似內存中業務對象集合的作用。
業務層與底層數據存儲機制進行了分離,業務層只是知道調用相應的respositoty就可以實現數據庫操作,它並不關心采用的是什么數據訪問技術和存儲介質,以及底層數據模型的結構差異是怎樣的。
2.2數據訪問對象模式
數據訪問對象(Data Access Object,DAO)模式是一種簡單的將數據訪問層與系統其它部分相隔離的設計方式。DAO和Respository很類似,就像我們初次學習Domain Model模式和ActiveRecord模式一樣,但是Dao沒有隱藏數據底層的相關信息,而且數據庫中的每一個表都存在一個DAO。
-
數據訪問層常用的模式與原則
3.1工作單元
維護受業務事務影響的對象列表,並且協調變化的寫入和解決並發問題。
工作單元就是記錄對象數據變化的對象,只要開始做一些可能對所要記錄的對象的數據有影響的操作,就會創建一個工作單元去記錄這些變化,所以每當創建、修改或者刪除一個對象的時候,就會通知工作單元。
工作單元的關鍵就是在提交操作中由它決定要做什么:打開一個系統事務,做並發檢查,最后向數據庫寫入所做的修改。要做到這一點,工作單元需要知道它應該記錄那些對象,以及如何記錄。有三種方式可以實現此功能:調用者注冊、對象自身注冊、respository注冊。
3.1.1調用者注冊
每當用戶改變某個對象時,必須將改變的對象注冊到工作單元中。任何沒有注冊的對象提交時都不會寫入數據庫。
3.1.2對象自身注冊
如果采用對象自身注冊的方式,調用者就不再負責注冊對象了,而是將注冊的方法置於對象本身的方法中。
一般做法如下:
-
將從數據庫加載的對象注冊為"干凈"的對象。
-
在對象屬性的set或其他修改對象值得方法中將對象注冊為"臟"對象。
-
在提交工作單元的時候,將會檢查所有提交的對象,並將"臟"的數據提交上去。
注意事項:
工作單元要么傳遞給對象,要么被放在一個總所周知、公共的地方。
對象的開發者必須記得在適當的地方加上注冊調用代碼。
3.1.3respository注冊方式
Respositoty就充當工作單元的角色。業務對象在獲取數據的時候總會獲取調用respository的方法,例如add,此時repositoty不會立即將業務對象數據保存到介質中,而是將對象保存到一個內存的additemlist中;如果調用delete方法,那么對象就保存到deleteitemlist中,最后調用respositoty的commit方法,將additemlsit和deleteitemlist中的數據作為一個事務提交。
工作單元不僅能作用於數據庫資源,還可以作用於任何事物資源,同時又可以用它來調整消息隊列和事務監控。
3.2標識映射
標識映射(Identity Map)就是通過在映射中保存每個已經加載的對象,從而確保每個對象只被加載一次。當要訪問對象時,可以通過映射來查找它們。
3.3延遲加載
延遲加載表示直到需要的時候才去加載所需要的資源。
實現延遲加載的方式有四種:延遲初始化、虛代理、值保持和重影。
虛代理看起來應該是我們需要的對象,但是實際上不包含任何東西,只有在調用它的方法時,它才會去加載恰當的對象。
代理的幾種方式:
遠程代理:為一個位於不同地址空間的對象提供一個局域代表對象。
虛代理:根據需要創建一個資源消耗較大的對象,也就是說此對象只有在需要的時候才會被真正創建出來。
Copy-on-write:虛擬代理的一種。把復制拖延到只有在客戶端需要時才真正采取行動。
保護訪問代理:控制對一個對象的訪問,如果需要,可以給不同的用戶提供不同級別的使用權限。保護代理的好處就是它可以在運行時對用戶的有關權限進行檢查,並在核實后決定是否將調用傳遞給被代理的對象。
Cache代理:為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以共享這些結果。
防火牆代理:保護目標,不讓惡意用戶接近。
同步化代理:使幾個用戶能夠同時使用一個對象而沒有沖突。
智能引用代理:當一個對象被引用時,提供一些額外的操作。
3.4數據並發控制
比較典型的解決方案有兩種:隔離和識別不變性。
所謂的"隔離",就是划分數據。通過把數據划分成很多的小片數據,來讓每一個分片都只能被一個執行單元訪問。隔離室減少錯誤發生幾率的一種很有效的技術,通過這種方法來安排資源,當程序進入隔離區時就無需考慮並發問題了。一個好的並發設計應該是:找到各種創建隔離區的辦法,並且保證在每個隔離區里面完成盡可能多的任務。
只有在共享數據可以被修改的時候,才會產生並發問題。所以另一個避免並發沖突的辦法就是標識出那些數據是不變的。當然,讓所有的數據都不變是不可能的,因為許多系統本來就要對很多數據進行修改。但是通過定義某些數據為不變,或者至少幾乎不變,或者變得頻率很低,就可以不用總考慮這些數據的並發性問題了。這就是所謂的"識別不變性"。
當有些可變的數據無法隔離時,可以采用兩種形式的並發控制策略:樂觀並發控制和悲觀並發控制。樂觀並發控制允許多個用戶同時對同一個數據進行修改,最后提交的修改被采納。悲觀並發控制每次只允許一個用戶對數據進行修改,與此同時其它多個用戶對數據享有"讀"的權限。
這兩種策略各有優缺點。悲觀並發控制降低了系統並發操作發生的頻繁程度。例如:當用戶A對某數據進行加鎖修改的時候,其它想修改該數據的用戶就只能等待了。樂觀並發控制則自有一些,多個用戶可以同時修改數據,只是在提交數據的時候會出現一些阻礙,因為很可能你提交的修改已經被其他用戶覆蓋了。
使用那種控制的標准是:根據沖突的頻率與嚴重性來決定。如果沖突很少,或者沖突的后果不嚴重,那么通常情況下應該選擇樂觀並發控制,因為它能夠得到更好的並發性,而且實現起來也比較容易。
一般來說,樂觀並發控制和悲觀並發控制都是將數據的沖突檢測建立在數據的某種版本標識上的,可能是時間戳,也可能是順序計數器。對於悲觀並發控制,在提交修改數據時,先比較此數據在數據源中的版本標識是否和提交的數據的標識一樣,如果一樣,那么將數據進行保存,否則,拒絕保存數據。
3.5查詢對象
查詢對象(query object)描述的是一次數據庫的查詢。查詢對象是解釋器模式在sql查詢上的應用。它使得客戶程序可以采用面向業務對象語言而不是數據庫語言來描述查詢。
只有使用領域模型和數據映射器時,才會真正的需要查詢對象。
4.ORM對象關系映射
Entity framework是微軟在.net平台下的一個重量級的ORM。EF不僅僅能夠在關系模型存儲介質和業務模型之間進行映射,也能在非關系數據存儲介質和業務模型之間進行映射。
如下圖所示: