1. 程式人生 > >.Net企業級應用架構設計之資料訪問層

.Net企業級應用架構設計之資料訪問層

綜述

資料訪問層的設計很大程度上取決於專案干係人需求的影響。例如,資料訪問層應該持久化物件模型還是簡單的的值的集合?資料訪問層應該支援一種資料庫還是多種資料庫?下面仔細分析資料訪問層的常見功能需求。

資料庫獨立性:資料訪問層是系統中唯一知道並使用連線字串和資料表名稱的地方,考慮到這些,資料訪問層必須要依賴於資料庫管理系統DBMS,對於外部觀察者,資料訪問層應該就像一個黑盒,可以插入到現有系統中,封裝了為某個特定DBMS實現的讀取和寫入的操作。

像外掛一樣可以配置:通常來說,資料庫獨立性需要使用一套普通的、跨資料庫的應用程式設計介面。在我們看來,實現真正資料庫獨立需要將資料庫訪問層作為一個黑盒,該黑盒提供了一個固定的介面,並從配置檔案中動態讀取出當前資料庫訪問層元件的細節。還有一種實現資料庫獨立性的做法是使用物件/關係對映工具(O/RM)。這時,O/RM提供一套公共的API,讓你僅需要簡單修改配置引數就可以切換到另一個數據庫,不過,有時候專案允許你使用O/RM,有時候卻不行(取決於專案干係人,都懂的,有可能是帶偏見的架構師,也有可能是不懂技術的客戶,還有可能是頭髮高聳的專案經理)。關於O/RM優劣的爭論這裡不做討論也不站隊。

持久化應用程式的物件模型:無論何種形式,資料訪問層都必須能夠持久化應用程式的資料。若必須提供物件模型,那麼資料訪問層要能夠將模型持久化至關係型結構中。當然,這會造成那個臭名昭著“物件/關係阻抗失調”問題。關係型資料庫實際上存放的資料元組,而物件模型則構造出一張物件圖,因此,兩個模型之間自然需要對映,這也是資料訪問層的主要功能。持久化應用程式的物件模型是指將資料載入至新建立物件模型和將某個例項的內容寫回資料庫的能力。無論選擇了什麼DBMS或物理上的表結構,持久化功能都不應該收到影響。依照領域模型模式設計的物件模型並不瞭解資料訪問層的存在,不過若物件模型屬於活動記錄,那麼資料訪問層內嵌在實現模型的所有框架中。

資料訪問層的職責

資料訪問層對使用者來說有四個職責。首先,資料訪問層需要將資料持久化至物理儲存中,併為外部世界提供CRUD服務。其次,資料訪問層還要處理其接收的所有資料相關的請求,資料訪問層必須滿足事務性需求。最後,資料訪問層也要合理的處理併發。從概念角度,資料訪問層可以看作是封裝了4中服務的黑箱。

若開發團隊在專案中自行建立資料訪問層,那麼就必須收工實現這些職責並頭從編寫程式碼。若可以選用O/RM工具,讓工具完成一些職責。

資料訪問層和其他層

資料訪問層和業務層:若你傾向於相對簡單的領域邏輯,那麼資料訪問層僅僅包含表介面卡,用來實用查詢從DBMS中獲取資料,並使用儲存過程或SQL命令將資料寫回資料庫。而對於事務指令碼模式,為了滿足業務邏輯,資料訪問層需要實現的僅僅是純粹的CRUD操作而已。在領域模型中,資料訪問層屬於業務層的一個補充,一般由服務層使用。

資料訪問層和服務層:若你擁有領域驅動的業務邏輯,那麼資料訪問層就可以作為持久化模型的工具。資料訪問層和領域模型並不直接通訊,而是靠服務層來協調,這也是架構上的關鍵之處。

資料訪問層和表現層:資料訪問層在理論上不可能觸及到表現層。在現實世界中,表現層也許會直接呼叫資料訪問層中的一些方法,這樣做的關鍵並不在於你能“投機取巧”的為某個問題找到了快速的解決方案,更加重要的是你必須意識帶你正在“投機取巧”。經驗告訴我們,若能從實際出發並恰到好處的控制此類表現層呼叫資料訪問層的做法,那麼結果非常不錯,這樣做也為兩個不想管的層之間添加了不應有的耦合,因此在需要時可以拿來急用,不過隨後要儘早重構。

資料訪問層的最終形態大多取決於架構師對業務層的設計,不過在某種程度上也會有反過來的效果,即資料訪問層也會影響到業務層,就像先有雞還是先有雞蛋這個古老的故事一樣。你所受到的限制和你的關注點決定了從哪部分開始設計,也就是決定了哪一層影響哪一層。事實上,業務邏輯層設計和資料訪問層設計模式之間僅有那麼幾種合理的組合。

設計自己的資料訪問層

首先並不建議架構師和開發者從頭到尾編寫一個數據訪問層,很多應用程式,哪怕是企業級應用也經常使用強型別DataSet或活動記錄物件模型,顯得太沒必要,O/RM工具已經提供了所有的功能。為了確保完全不依賴於資料庫結構,資料訪問層和其使用者將使用業務實體(領域物件、活動記錄模型中的物件、強型別DataSet或普通的資料遷移物件)來通訊。這麼做優勢有很多,最明顯的是這樣的應用程式可以更容易的支援多種資料來源。分離介面模式也規範了這種將資料訪問層介面和實現分離開的設計原則。提取介面能夠簡化測試,這是個很好的理由。通常來說,分離介面模式實現了一個更加分層的設計,降低了資料訪問層也其使用者之間的耦合,這樣做總不是一件壞事。

是否該使用儲存過程

1、傳言:儲存過程要比SQL程式碼執行效率更高:所謂的儲存過程要比普通SQL有效能提升體現在對執行計劃的重用上,換句話說,第一次執行儲存過程時,資料庫將生成執行計劃,然後執行程式碼。下一次執行時即可重用前面已經生成的執行計劃,因此效率上會有所提高。所有的SQL命令都需要執行計劃。在SQLServer2005線上文件中的一段引文:“在SQL Server 2005執行任何SQL語句時,關係引擎首先檢視快取,判斷其中是否有當前SQL的執行計劃,SQL Server 2005將重用任何可執行的執行計劃,以便減小重新編譯SQL語句對效能上的影響。若沒有找到現有執行的計劃,SQL Server 2005才會為當前查詢生成新的執行計劃”。從效能角度考慮,所有到達資料庫的SQL程式碼都會被同等對待,編譯之後,二者效能沒有任何差別。

2、傳言:儲存過程要比SQL程式碼安全:在執行任何SQL語句之前,資料庫引擎都會嘗試匹配呼叫者提供的認證資訊和所請求資源的訪問許可權。根據匹配結果,引擎將決定是否執行該語句。這樣看來,從安全形度儲存過程顯然比普通SQL程式碼更有優勢。但是安全性是個橫切的關注點,應該從表現層到資料庫的各層中都有處理。今天,基於角色的安全是最靈活且最有效的做法。在基於角色的安全模型中,我們對安全性有著雙重的保證,第一重是中間層中使用基於角色的安全,第二充實資料庫引擎的宣告式安全。若將儲存過程作為整個系統的核心,那麼必定會讓人做出不好的設計決定。你可以使用儲存過程,但不要說是出於安全性考慮,也不要用儲存過程來實現邏輯。

3、傳言:儲存過程可用來阻擋SQL的注入攻擊:儲存過程當然可以降低SQL注入發生的可能,因為儲存過程使用強型別引數。使用引數構造的SQL語句也可以和儲存過程一樣阻擋SQL的注入攻擊。

4、傳言:儲存過程可以讓SQL程式碼更加穩定不易改變:這是以前設計方式的產物,即資料庫開發人員和其他開發人員基本沒有溝通。若真想不依賴物理資料模型,那麼應該選擇領域驅動設計,將資料庫設計成一個簡單的持久化層。

小結

對領域驅動設計的需要,隨之而來的是以更加概念化的方式操作資料,資料庫的角色也不可避免的降低成了一個持久化工具。

相關部落格: