新聞中心
一、上章回顧

創(chuàng)新互聯(lián)專注于北屯網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供北屯營(yíng)銷型網(wǎng)站建設(shè),北屯網(wǎng)站制作、北屯網(wǎng)頁(yè)設(shè)計(jì)、北屯網(wǎng)站官網(wǎng)定制、微信小程序定制開發(fā)服務(wù),打造北屯網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供北屯網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
上篇我們簡(jiǎn)單講述了服務(wù)層架構(gòu)模式中的幾種,并且講解了服務(wù)層的作用及相關(guān)的設(shè)計(jì)規(guī)范,其實(shí)我們應(yīng)該知道,在業(yè)務(wù)邏輯層中使用領(lǐng)域模型中使用服務(wù)層才
能發(fā)揮出***的優(yōu)勢(shì),如果說我們?cè)跇I(yè)務(wù)邏輯層還是使用非領(lǐng)域模型的模式話,服務(wù)層的作用僅體現(xiàn)在解耦作用。其實(shí)在業(yè)務(wù)邏輯層采用領(lǐng)域模型時(shí),我們前面說的持
久化透明的技術(shù),其實(shí)我們可以通過服務(wù)層來做,我們?cè)诜?wù)層中處理領(lǐng)域?qū)ο笮畔⒌某志没僮?。?dāng)然本篇可能不會(huì)深入討論持久化透明的具體實(shí)現(xiàn),后面會(huì)單獨(dú)開
篇來講述,我們先來回顧下上篇講解的內(nèi)容:
上圖大概描述了上篇我們講解的內(nèi)容,如果您想要詳細(xì)的了解服務(wù)
層的相關(guān)內(nèi)容,請(qǐng)參考:系統(tǒng)架構(gòu)師-基礎(chǔ)到企業(yè)應(yīng)用架構(gòu)-服務(wù)層,后續(xù)我們將會(huì)對(duì)一些前端的服務(wù)層還會(huì)進(jìn)行擴(kuò)展的講解,請(qǐng)大家提出報(bào)告意見和建議。
二、摘要
本篇將主要以系統(tǒng)中與數(shù)據(jù)庫(kù)存儲(chǔ)介質(zhì)進(jìn)行交互的數(shù)據(jù)訪問層進(jìn)行詳細(xì)的介紹講解,我想這塊也是大家比較熟悉也是經(jīng)常在項(xiàng)目中一定會(huì)用到的部分,我們知道
數(shù)據(jù)訪問層通常我們都把這塊的內(nèi)容提升出來,寫成通用的類庫(kù),在我們前面講解的分層架構(gòu)的系統(tǒng)中,基本上可以說業(yè)務(wù)對(duì)象中的數(shù)據(jù)都要通過數(shù)據(jù)訪問層將業(yè)
務(wù)數(shù)據(jù)持久化到存儲(chǔ)介質(zhì)中。其實(shí)目前有很多的好的ORM框架已經(jīng)很好的實(shí)現(xiàn)了數(shù)據(jù)訪問層,而且得到了很廣泛的應(yīng)用,當(dāng)然我們本篇也會(huì)以這些通用的框架為例舉
例說明數(shù)據(jù)訪問層中的一些設(shè)計(jì)模式。本章將會(huì)以下列幾個(gè)典型關(guān)注點(diǎn)展開去講:
1、數(shù)據(jù)訪問層的職責(zé)及與其他組件的交互。
2、如何設(shè)計(jì)自己的數(shù)據(jù)訪問層。
3、實(shí)現(xiàn)數(shù)據(jù)訪問層必須滿足的4個(gè)基本要求,持久化CRUD、查詢服務(wù)、事務(wù)服務(wù)、實(shí)現(xiàn)并發(fā)等。
4、結(jié)合目前流行的幾類框架分析框架提供的數(shù)據(jù)訪問層功能的優(yōu)劣。
下面我們將針對(duì)上面的幾個(gè)關(guān)注點(diǎn)依次展開去說,希望能通過本文的講解,讓您對(duì)數(shù)據(jù)庫(kù)訪問層有個(gè)更深刻的認(rèn)識(shí)和了解。
三、本章大綱
1、上章回顧。
2、摘要。
3、本章大綱。
4、數(shù)據(jù)訪問層介紹。
5、如何設(shè)計(jì)數(shù)據(jù)訪問層。
6、實(shí)現(xiàn)數(shù)據(jù)訪問的四項(xiàng)原則。
7、本章總結(jié)。
8、系列進(jìn)度。
9、下篇預(yù)告。
四、數(shù)據(jù)庫(kù)訪問層簡(jiǎn)介
本節(jié)將會(huì)主要針對(duì)數(shù)據(jù)訪問層的功能及職責(zé)進(jìn)行講解,分析之前在業(yè)務(wù)邏輯層中的四種模式與數(shù)據(jù)訪問層之間的關(guān)系。我們閑來看看數(shù)據(jù)訪問層與業(yè)務(wù)邏輯層中的
四種模式之間的關(guān)系。
我們?cè)诒竟?jié)中的講解主要是以領(lǐng)域模型為例進(jìn)行分析講解,因?yàn)橹挥蓄I(lǐng)域模型模式,我們才能將數(shù)據(jù)訪問層抽離出來,分成單獨(dú)的層,這樣能夠做到領(lǐng)域?qū)ο蟪志?/p>
化透明。接下來我們來看看數(shù)據(jù)訪問層都需要提供什么要的功能及數(shù)據(jù)訪問層本身的職責(zé)是什么。
數(shù)據(jù)庫(kù)訪問層是唯一知道如何操作存儲(chǔ)介質(zhì)的入口,可以這么來說,基于數(shù)據(jù)訪問層之上,我們調(diào)用數(shù)據(jù)庫(kù)訪問層提供的方法,我們就能完成數(shù)據(jù)的存儲(chǔ)與讀取,
所以我們可以知道,數(shù)據(jù)訪問層應(yīng)該是與數(shù)據(jù)庫(kù)直接是獨(dú)立的。還有就是我們的數(shù)據(jù)訪問層如何能實(shí)現(xiàn)不同類型的數(shù)據(jù)庫(kù)的動(dòng)態(tài)的切換,而我們不需要修改任何的程序
功能等,可能我們?cè)陂_發(fā)的過程中都會(huì)遇到這樣的問題。所以我們希望可以對(duì)數(shù)據(jù)訪問層完成動(dòng)態(tài)的配置,通過不同的配置項(xiàng)完成對(duì)象數(shù)據(jù)庫(kù)訪問的切換,這里我想大
家都是比較熟悉的,通過XML配置文件來完成數(shù)據(jù)庫(kù)的切換,前面我們說了我們的需求,是必須實(shí)現(xiàn)無縫的數(shù)據(jù)庫(kù)的切換,那么我們?nèi)绾螌?shí)現(xiàn)呢,這里我們可以通過定
義一個(gè)數(shù)據(jù)庫(kù)訪問接口,然后通過實(shí)現(xiàn)不同的數(shù)據(jù)庫(kù)的細(xì)節(jié),來實(shí)現(xiàn)這樣的切換。目前很多流行的框架都是采用這樣的方式來實(shí)現(xiàn)數(shù)據(jù)庫(kù)的動(dòng)態(tài)切換。當(dāng)然有時(shí)候我們
的項(xiàng)目中肯能不讓我們使用開源的通用框架,這時(shí)候我們可能就需要自己去實(shí)現(xiàn)這些數(shù)據(jù)訪問層的具體細(xì)節(jié)。
當(dāng)然數(shù)據(jù)訪問層都必須能夠?qū)?yīng)用程序中的數(shù)據(jù)持久化到存儲(chǔ)介質(zhì)中,通常我們使用的數(shù)據(jù)都是關(guān)系型的數(shù)據(jù)庫(kù),但是我們知道我們?cè)诔绦虻拈_發(fā)中,通常采用的
模型都是對(duì)象模型,那么如何實(shí)現(xiàn)對(duì)象模型與關(guān)系模型直接的互相的轉(zhuǎn)換就顯得非常的重要。當(dāng)然這是數(shù)據(jù)訪問層的重要功能。通常來說,業(yè)務(wù)邏輯層及服務(wù)層不了解
數(shù)據(jù)庫(kù)訪問的具體細(xì)節(jié),他們都需要通過數(shù)據(jù)訪問層來實(shí)現(xiàn)數(shù)據(jù)的交互。一般來說在領(lǐng)域模型中,數(shù)據(jù)訪問通常都是在服務(wù)層中進(jìn)行調(diào)用的,而業(yè)務(wù)邏輯層并不關(guān)注數(shù)
據(jù)持久化,所以我們前面說的持久化透明的方式也是由此方式來實(shí)現(xiàn)。
上面我們啰嗦了一大堆,基本上說了數(shù)據(jù)訪問層的基本需求功能:
下面我們來看看數(shù)據(jù)訪問層的幾個(gè)基本職責(zé)
首先、數(shù)據(jù)訪問層應(yīng)該提供基本的持久化操作CRUD的操作,我們知道數(shù)據(jù)訪問層是唯一能操作數(shù)據(jù)庫(kù)的一層,因?yàn)槲覀冊(cè)谠O(shè)計(jì)時(shí)需要注意,系統(tǒng)的其他層不能
包含操作數(shù)據(jù)庫(kù)的相關(guān)功能
這里我們通過類圖可以看到,通過提供與類對(duì)應(yīng)的數(shù)據(jù)庫(kù)操作類來提供
相應(yīng)的持久化操作方法,當(dāng)然這不是唯一方式,可行的方式有很多。我們后面會(huì)詳細(xì)討論。
其次、應(yīng)該提供能夠滿足類中信息的讀取操作,一般情況下來說我們經(jīng)常使用的是,根據(jù)主鍵查詢某個(gè)對(duì)象的信息,或者是查詢所有的記錄,或者是根據(jù)條件返
回滿足的集合。
當(dāng)然我們這里定義的查詢類可能是通用的形式,通過泛型的形式來做。但是我們知道
領(lǐng)域模型中肯定會(huì)有引用對(duì)象的情況,那么對(duì)于這樣的情況我們?nèi)绾蝸碜瞿??我們一般是通過延遲加載的形式來處理這樣的要求,我們后面會(huì)依次講解。我們來看看上
面的通用形式的簡(jiǎn)單代碼格式:
- public class QueryHelper
- {
- ///
- /// 根據(jù)主鍵返回對(duì)象
- ///
- ///
- ///
- ///
- public T GetObjectByKey
(object key) - {
- return default(T);
- }
- ///
- /// 獲取指定類型對(duì)象的總記錄數(shù)
- ///
- ///
- ///
- ///
- public int GetCount
(object key) - {
- return 0;
- }
- ///
- /// 返回指定類型的所有對(duì)象集合
- ///
- ///
- ///
- public List
GetAll () - {
- return new List
(); - }
- }
再次、數(shù)據(jù)庫(kù)訪問必須提供事務(wù)的管理,可以說不提供事務(wù)操作的數(shù)據(jù)訪問層就沒有辦法使用,因?yàn)檫@樣的數(shù)據(jù)訪問層構(gòu)建的系統(tǒng)是不安全的。特別是批量持久
化的過程中,事務(wù)不但能夠減少與數(shù)據(jù)庫(kù)操作的次數(shù),而且根據(jù)事務(wù)的四個(gè)特性可以提供更好的安全性。我們來回顧下事務(wù)的四個(gè)特性:
我想我這里就不用一一解釋了,大家都明白的。我們?cè)跀?shù)據(jù)訪問層的設(shè)計(jì)中是通過引入
“工作單元”來實(shí)現(xiàn)事務(wù)管理的,工作單元后面會(huì)講述到工作單元內(nèi)提供的方法及事務(wù)性。
***、數(shù)據(jù)訪問層必須提供處理并發(fā)的功能,我們?cè)谙到y(tǒng)訪問的人較多的情況時(shí)肯定會(huì)出現(xiàn)并發(fā)的情況,數(shù)據(jù)訪問層如何處理這樣的情況就顯得極其重要了,在
一個(gè)多用戶并發(fā)的系統(tǒng)中,通過前面提到的事務(wù)來處理,這時(shí)候可能就會(huì)出現(xiàn)數(shù)據(jù)庫(kù)完整性的問題,例如這樣的情況,一個(gè)用戶現(xiàn)在在編輯自己的個(gè)人信息,例如將生
日修改為1985年3月20日,這個(gè)用戶對(duì)應(yīng)的ID是298,這時(shí)候他只是修改了,但是還沒有提交,此時(shí)管理員也修改了,比如說修改了ID為298的這個(gè)用戶信息的地址或
者其他信息,并且提交,此時(shí),用戶將自己編輯的生日提交了,那么數(shù)據(jù)庫(kù)中對(duì)應(yīng)的ID為298的數(shù)據(jù)信息就會(huì)是***修改的數(shù)據(jù)信息,那么之前管理員修改的數(shù)據(jù)信息
就會(huì)發(fā)生丟失,雖然是修改的可能字段不是同一個(gè)字段,這就和我們底層實(shí)現(xiàn)的數(shù)據(jù)訪問層有關(guān),當(dāng)然如果說我們?cè)跀?shù)據(jù)訪問層實(shí)現(xiàn)了,只更新修改過的數(shù)據(jù)列的值的
話,那么可能不會(huì)存在這樣的情況,當(dāng)然這就和我們底層實(shí)現(xiàn)的數(shù)據(jù)訪問層的機(jī)制有關(guān)。
下面我們通過圖形的方式來說明,更容易理解:
我們來看看可能的幾種方案,可以對(duì)這樣的并發(fā)做出相應(yīng)的處理?
當(dāng)然這里只是提供了幾個(gè)簡(jiǎn)單可行的辦法,當(dāng)然如果大家還
有更好的辦法,可以告訴我,不勝感激。
當(dāng)然上面的四個(gè)基本職責(zé)是我們?cè)跀?shù)據(jù)訪問層必須提供的,還應(yīng)該提供緩存機(jī)制,延遲加載等等包括一些性能方面的優(yōu)化的設(shè)計(jì)等,這些都在后面講解吧。
下面我們來看看數(shù)據(jù)訪問層與其他層直接的關(guān)系與交互,我們前面說過,在領(lǐng)域模型下,業(yè)務(wù)邏輯層中的數(shù)據(jù)的持久化都是通過服務(wù)層來完成的,下面我們來看
看各層之間的關(guān)系。我們先來看看服務(wù)層與數(shù)據(jù)訪問層之間的關(guān)系。
服務(wù)層與數(shù)據(jù)訪問層之間進(jìn)行交互,服務(wù)層通過DTO與UI層進(jìn)行交互,服務(wù)層通過組織業(yè)務(wù)邏輯層中的對(duì)象來實(shí)
現(xiàn)業(yè)務(wù)流,然后通過調(diào)用數(shù)據(jù)訪問層將業(yè)務(wù)流中的相應(yīng)數(shù)據(jù)進(jìn)行持久化,通過數(shù)據(jù)訪問層來初始化領(lǐng)域模型。置于直接在表現(xiàn)層中使用數(shù)據(jù)訪問層的功能,我們通常是
不推薦這樣做的,一般我們不會(huì)這么做的,我這里就不詳細(xì)的闡述。
五、如何設(shè)計(jì)數(shù)據(jù)訪問層
本節(jié)將詳細(xì)的講述如何設(shè)計(jì)出自己的數(shù)據(jù)訪問層,滿足上述的幾個(gè)基本要求,那么可以說就算完成了基本的數(shù)據(jù)訪問層的功能,其實(shí)如果我們從頭開始開發(fā)一個(gè)
這樣的數(shù)據(jù)訪問層將是非常大的工作量,目前流行的很多的ORM框架已經(jīng)提供了豐富的數(shù)據(jù)訪問層的功能,能夠非常好的滿足上述的幾項(xiàng)職責(zé)。當(dāng)然本節(jié)還是會(huì)結(jié)合代
碼來說說數(shù)據(jù)訪問層的具體實(shí)現(xiàn)。
我們前面講述了數(shù)據(jù)訪問的3個(gè)基本的功能需求,數(shù)據(jù)庫(kù)獨(dú)立性,可配置性及持久化對(duì)象模式(對(duì)象模型與關(guān)系模型的轉(zhuǎn)換),我們這里先看如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的獨(dú)立
性,我們提出滿足數(shù)據(jù)庫(kù)的無縫遷移,通過XML配置文件,配置不同的數(shù)據(jù)庫(kù)鏈接來實(shí)現(xiàn)這樣的功能,那么首先我們需要定義針對(duì)不同數(shù)據(jù)庫(kù)具體實(shí)現(xiàn),才能完成后續(xù)
的操作,既然我們這里要降低耦合,那么根據(jù)我們前面的面向?qū)ο蟮脑O(shè)計(jì)原則與規(guī)范知道,我們推薦使用面向接口的編程的方式,來盡量的降低耦合性。我們來看看具
體的代碼。首先我們定義一個(gè)通用的數(shù)據(jù)訪問層的接口。
- ///
- /// 數(shù)據(jù)訪問層統(tǒng)一接口
- ///
- public interface IDALInterface
- {
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- int Create(object model);
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- int Update(object model);
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- int Delete(object model);
- //R 查詢服務(wù)
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- IList
GetAll () where T : class,new(); - ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- IList
GetListByQuery (WhereCondition whereCondition) where T : class,new(); - ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- int GetCount
(); - ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- int GetCount
(WhereCondition whereCondition); - ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- T GetModelByKey
(object key) where T : class,new(); - //事務(wù)
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- bool IsTransaction
- {
- get;
- }
- ///
- /// 開始事務(wù)
- ///
- void BeginTransaction();
- ///
- /// 提交事務(wù)
- ///
- void Commit();
- ///
- /// 回滾事務(wù)
- ///
- void Rollback();
- }
這里定義了基本的幾個(gè)簡(jiǎn)單方法,當(dāng)然其中并沒有包括并發(fā)的處理,后面會(huì)講到這塊的處理方案的實(shí)現(xiàn), 前面介紹了幾種可行的實(shí)現(xiàn)方式。接口定義好了之后,
數(shù)據(jù)層的具體代碼我這里就不一一的定義貼出來了,因?yàn)槊糠N不同的數(shù)據(jù)庫(kù)類型就要分別實(shí)現(xiàn),我們這里講解2中不同類型的實(shí)現(xiàn)思路吧,
我們這里講解2中實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建具體數(shù)據(jù)訪問組件的方式,我們先來講講插件模式。
插件模式
插件模式:插件模式就是通過外部配置文件中讀取要?jiǎng)?chuàng)建的組件的類型信息,然后調(diào)用組件服務(wù),插件模式的關(guān)鍵點(diǎn)就是服務(wù)不會(huì)與具體實(shí)現(xiàn)聯(lián)系起來,在我們的
分層結(jié)構(gòu)中的解釋就是,服務(wù)層中調(diào)用數(shù)據(jù)訪問層中的組件服務(wù),服務(wù)層不關(guān)系具體的調(diào)用方式,服務(wù)層只關(guān)心服務(wù)。而具體的數(shù)據(jù)訪問組件是通過配置文件來動(dòng)態(tài)的
創(chuàng)建,當(dāng)然這就需要使用.NET中的反射的功能。我們來看個(gè)圖形畫的描述:
反射工廠通過讀取配置文件中具體的數(shù)據(jù)配置項(xiàng)及數(shù)據(jù)訪問的具
體服務(wù)組件類型,通過反射工廠來動(dòng)態(tài)的創(chuàng)建,好了我們來看看實(shí)例代碼及配置文件。
- value="Data Source=.SQLEXPRESS;Initial Catalog=EasyStore;User ID=sa;Password=123456" />
- value="Data Source=.SQLEXPRESS;Initial Catalog=EasyStore;User ID=sa;Password=123456" />
- value="DAL.SQLServer" /> value="DAL.SQLServer" />
- value="DAL.SQLServer" /> value="DAL.SQLServer" />
上面的配置文件中的ConnectionItem 節(jié)點(diǎn)中配置了數(shù)據(jù)庫(kù)訪問的鏈接字符串,DALType 定義了數(shù)據(jù)訪問層組件的類型。我們下來看看反射工廠的示例代碼實(shí)
現(xiàn)。
- public class DALHelper
- {
- private static IDALInterface instance;
- public static IDALInterface GetDAL()
- {
- string assambly = XmlHelper.getVlaue("Assembly");//這里應(yīng)該是自定義的讀取XML節(jié)點(diǎn)的方式
- string type = XmlHelper.getVlaue("DALType");
- Assembly asm = Assembly.Load(assambly);
- instance = (IDALInterface)asm.CreateInstance(type);
- return instance;
- }
- }
我們接下來看看如何使用這個(gè)數(shù)據(jù)訪問層去實(shí)現(xiàn)相應(yīng)的持久化操作:
- public class TestService
- {
- private IDALInterface DAL;
- public TestService()
- {
- DAL = DALHelper.GetDAL();
- }
- public void Create(Test test)
- {
- //相應(yīng)的判定操作
- //創(chuàng)建對(duì)象
- DAL.Create(test);
- }
- }
這樣就實(shí)現(xiàn)了在服務(wù)層對(duì)數(shù)據(jù)訪問層的調(diào)用操作,這里是通過接口調(diào)用的方式來實(shí)現(xiàn)。我們?cè)賮砜纯纯刂品崔D(zhuǎn)的實(shí)現(xiàn)方式吧。
控制反轉(zhuǎn)
控制反轉(zhuǎn)我們?cè)谠O(shè)計(jì)規(guī)范與原則中有過講解,控制反正通過動(dòng)態(tài)的將組件注入到引用該組件的對(duì)象中的形式,然后讓引用該組件的對(duì)象使用組件的服務(wù),DI依賴注
入可以看作是控制反轉(zhuǎn)的一個(gè)應(yīng)用實(shí)例,我們可以把控制反轉(zhuǎn)看作是一個(gè)原則。
下面我們來看看我們?nèi)绾瓮ㄟ^控制反正的方式來實(shí)現(xiàn)數(shù)據(jù)訪問層的平滑遷移。當(dāng)然我們知道,肯定是通過動(dòng)態(tài)注入的方式來實(shí)現(xiàn),當(dāng)然目前主流的也有很多的IOC動(dòng)
態(tài)注入框架,下面我們將會(huì)借助一些框架來說明如何實(shí)現(xiàn)這樣的功能。
本文將以Enterprise Library5.0為例進(jìn)行講解動(dòng)態(tài)注入的形式。我們先來看看配置文件的設(shè)置
我們來看看通過一個(gè)中間類去實(shí)現(xiàn)相應(yīng)的注冊(cè)代碼:
- ///
- /// 用于動(dòng)態(tài)完成代碼注入的公共類
- ///
- public class IOCContainer
- {
- private static IUnityContainer container;
- private UnityConfigurationSection section;
- public void InitIOC()
- {
- container = new UnityContainer();
- section = (UnityConfigurationSection)System.Configuration.ConfigurationManager.GetSection("unity");
- section.Configure(container);
- }
- public static IDALInterface GetDAL()
- {
- return container.Resolve
(); - }
- }
通過上述代碼我們實(shí)現(xiàn)了,動(dòng)態(tài)的創(chuàng)建數(shù)據(jù)訪問層組件實(shí)例,下面我們來看看依賴注入的方式去完成相應(yīng)的持久化的功能。我們來看看服務(wù)層的代碼
- ///
- /// 測(cè)試服務(wù)層
- ///
- public class TestService
- {
- private IDALInterface DAL;
- public TestService(IDALInterface dal)
- {
- DAL = dal;
- }
- public void Save(Test test)
- {
- DAL.Create(test);
- }
- }
這里我們是采用構(gòu)造函數(shù)注入的方式來實(shí)現(xiàn)數(shù)據(jù)訪問層的動(dòng)態(tài)注入的,當(dāng)然除了構(gòu)造函數(shù)注入,還有其他的方式,我們這里只是舉例說明,一般來說依賴注入有
如下的幾種形式
具體的我這里就不舉例說明了,大家可以網(wǎng)上查查有很多的例
子,我們平時(shí)也常用這些方式。
六、實(shí)現(xiàn)數(shù)據(jù)訪問的四項(xiàng)原則
在第四節(jié)中我們講解了數(shù)據(jù)訪問層的四個(gè)原則,那么我們?cè)谧约旱臄?shù)據(jù)訪問層中如何實(shí)現(xiàn)這幾個(gè)原則呢,我想針對(duì)***個(gè)原則持久化的原則,我們前面只是簡(jiǎn)單
的講解如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的獨(dú)立性,下面我們先來看看持久化的操作,也就是我們說的CUD的操作,并不包括具體的查詢服務(wù),查詢服務(wù)也是我們數(shù)據(jù)訪問層必須提供四
個(gè)原則之一,我們后面都會(huì)講解,我們先來看看CUD的實(shí)現(xiàn)。我們?cè)谧龀志没?wù)的時(shí)候,一般情況下,我們會(huì)定義一個(gè)統(tǒng)一的數(shù)據(jù)訪問層接口,然后提供持久化服
務(wù),事務(wù)等等,通常有一些數(shù)據(jù)訪問層共性的部分,我們都通過一個(gè)抽象類來實(shí)現(xiàn),抽象類將實(shí)現(xiàn)接口中的部分功能,然后通過定義一些抽象成員函數(shù),讓具體的數(shù)據(jù)
訪問層去實(shí)現(xiàn)相應(yīng)的功能。我們這里以上節(jié)我們定義的IDALInterface為例講解基類的簡(jiǎn)單實(shí)現(xiàn)。
我們將原來的接口層進(jìn)行相關(guān)的優(yōu)化操作將CUD操作單獨(dú)抽取出來,通過ICUDMapper接口來定義
- ///
- /// 數(shù)據(jù)庫(kù)持久化訪問器
- ///
- public interface ICUDMapper
- {
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- int Create(object model);
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- int Update(object model);
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- int Delete(object model);
- }
然后我們來看看基類接口層的簡(jiǎn)單實(shí)現(xiàn),作為所有數(shù)據(jù)訪問層的父類
- public abstract class BaseDAL : IDALInterface,IDisposable
- {
- protected abstract ICUDMapper GetMapper();
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- public int Create(object model)
- {
- return GetMapper().Create(model);
- }
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- public int Update(object model)
- {
- return GetMapper().Update(model);
- }
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- public int Delete(object model)
- {
- return GetMapper().Delete(model);
- }
- #region IDisposable 成員
- ///
- /// 是否數(shù)據(jù)庫(kù)訪問組件資源
- ///
- public void Dispose()
- {
- }
- #endregion
- }
當(dāng)然這里只貼出實(shí)例代碼。當(dāng)然我采用這樣的方式,就是利用我們之前的一篇:Step by Step-構(gòu)建自己的ORM系列-開篇這篇中的反射的思想,大家可以看看
特性+反射的思路,我這里的數(shù)據(jù)持久化訪問器也是類似的操作,可能底層的實(shí)現(xiàn)就是這樣的方式。
具體的數(shù)據(jù)持久化訪問器如何動(dòng)態(tài)的生成SQL語(yǔ)句,緩存優(yōu)化等各方面的內(nèi)容,我們本篇可能不會(huì)深入的講解,我還是想將這塊放在ORM系類篇深入講解。
當(dāng)然我們其實(shí)可能極端的做飯就是為每個(gè)領(lǐng)域模型中的對(duì)象建立一個(gè)數(shù)據(jù)持久化映射器,完成映射,我這里則是通過創(chuàng)建數(shù)據(jù)庫(kù)的統(tǒng)一模式,在具體的映射器中,
通過反射取得數(shù)據(jù)對(duì)象的映射信息。我們來看看實(shí)現(xiàn)的思路吧,具體代碼我就不貼了
大體的流程就是上面說的了,細(xì)節(jié)肯定還有很多要注意的地方。
下面我們來看看查詢服務(wù)的實(shí)現(xiàn):
我想一般的系統(tǒng)80%的時(shí)間數(shù)據(jù)庫(kù)執(zhí)行的操作是查詢,而20%的時(shí)間在完成寫入和修改的操作,當(dāng)然我這里不是絕對(duì)的說法。我們希望有一個(gè)工具幫我們自動(dòng)完
成基本的查詢服務(wù),而不是我們手動(dòng)的去書寫,因?yàn)槲覀儼l(fā)現(xiàn)對(duì)大部分的數(shù)據(jù)集合而言,有一些共性的操作,例如獲取某個(gè)主鍵值的對(duì)象的信息,或者是獲取數(shù)據(jù)庫(kù)表
中的總行數(shù),或者是返回?cái)?shù)據(jù)庫(kù)表的所有記錄,并且如何將關(guān)系數(shù)據(jù)庫(kù)中的關(guān)系模型轉(zhuǎn)換為對(duì)象模型,這都是查詢服務(wù)中應(yīng)該提供的基本功能。下面我們來看看簡(jiǎn)單實(shí)
現(xiàn)吧。
我想我們還是參考前面的方式,我們將IDALInterface層中的查詢服務(wù)進(jìn)行抽象分離,將查詢服務(wù)單獨(dú)提出來放在接口IQuery中。代碼如下:
- public interface IQuery
- {
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- IList
GetAll () where T : class,new(); - ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- IList
GetListByQuery (WhereCondition whereCondition) where T : class,new(); - ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- int GetCount
(); - ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- int GetCount
(WhereCondition whereCondition); - ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- T GetModelByKey
(object key) where T : class,new(); - }
我們來看看在基類中的實(shí)現(xiàn)。查詢服務(wù)的相關(guān)實(shí)現(xiàn)
- ///
- /// 查詢服務(wù)組件
- ///
- ///
- protected abstract IQuery GetQuery();
- #region IQuery 成員
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- public IList
GetAll () where T : class,new() - {
- return GetQuery().GetAll
(); - }
- ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- public IList
GetListByQuery (WhereCondition whereCondition) where T : class,new() - {
- return GetQuery().GetAll
(); - }
- ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- public int GetCount
() - {
- return GetQuery().GetCount
(); - }
- ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- public int GetCount
(WhereCondition whereCondition) - {
- return GetQuery().GetCount
(whereCondition); - }
- ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- public T GetModelByKey
(object key) where T : class,new() - {
- return GetQuery().GetModelByKey
(key); - }
- #endregion
當(dāng)然根據(jù)不同的數(shù)據(jù)庫(kù)可能定義的查詢語(yǔ)句的格式不同,但是返回的結(jié)果的形式卻可以定義成通用的形式。這樣我們就可以實(shí)現(xiàn)比較通用的查詢服務(wù),也有很好
的通用型和擴(kuò)展性。當(dāng)然我們這里還可以添加分頁(yè)的支持等,只是添加的條件有限制,實(shí)現(xiàn)方式還是相同。
下面我們來看看數(shù)據(jù)訪問層功能必須職責(zé)之事務(wù)性,我們都知道事務(wù)性的幾大特性,通過事務(wù)性來提供數(shù)據(jù)的安全性。我們這里給出一種思路去實(shí)現(xiàn)這樣的事務(wù)
性,我們?cè)跀?shù)據(jù)訪問層中定義一組事務(wù)單元,通過一個(gè)列表維護(hù)這些事務(wù)單元,當(dāng)執(zhí)行提交時(shí),我們將這個(gè)事務(wù)范圍內(nèi)的所有事務(wù)單元進(jìn)行提交,否則不進(jìn)行真正的提
交操作。我們來看看吧,我們?cè)谥暗腎DALInterface中已經(jīng)定義了事務(wù)相關(guān)的幾個(gè)方法,我們這里同樣抽出來,進(jìn)行分解,抽出來一個(gè)單獨(dú)的接口ITransation,具體
代碼如下:
- public interface ITransaction
- {
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- bool IsTransaction
- {
- get;
- }
- ///
- /// 開始事務(wù)
- ///
- void BeginTransaction();
- ///
- /// 提交事務(wù)
- ///
- void Commit();
- ///
- /// 回滾事務(wù)
- ///
- void Rollback();
- }
基類中的代碼如下:
- #region ITransaction
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- public bool IsTransaction
- {
- get
- {
- return GetTransaction().IsTransaction;
- }
- }
- ///
- /// 開始事務(wù)
- ///
- public void BeginTransaction()
- {
- GetTransaction().BeginTransaction();
- }
- ///
- /// 提交事務(wù)
- ///
- public void Commit()
- {
- GetTransaction().Commit();
- }
- ///
- /// 回滾事務(wù)
- ///
- public void Rollback()
- {
- GetTransaction().Rollback();
- }
- ///
- /// 返回事務(wù)單元列表
- ///
- List
list - {
- get;
- }
- ///
- /// 執(zhí)行事務(wù)單元的操作,執(zhí)行數(shù)據(jù)操作并提交
- ///
- ///
- void Excute(TransationUnit unit);
- #endregion
- ///
- /// 事務(wù)組件服務(wù)
- ///
- ///
- protected abstract ITransaction GetTransaction();
事務(wù)組件中添加了特殊的事務(wù)單元,用來存儲(chǔ)事務(wù)執(zhí)行的操作CUD,還有就是要事務(wù)執(zhí)行的數(shù)據(jù)對(duì)象,當(dāng)然事務(wù)對(duì)象中的CRD操作就是使用前面講解的CRD操作
的方式,我們來看看吧,我們來看看事務(wù)單元的形式。
- ///
- /// 事務(wù)單元
- ///
- public class TransationUnit
- {
- ///
- /// CUD枚舉
- ///
- public enum CUDEnum
- {
- Create,
- Update,
- Delete
- }
- private CUDEnum _cudType;
- private object _model;
- public TransationUnit(object model, CUDEnum cudType)
- {
- _model = model;
- _cudType = cudType;
- }
- }
我們?cè)谑聞?wù)處理中,我們只執(zhí)行事務(wù)列表中的操作,置于非事務(wù)列表中的單元我們將不做任何處理,所以我們只要是事務(wù)執(zhí)行的事務(wù)單元,我們必須將指定操作類
型,當(dāng)然我們還可以更靈活,我們通過在事務(wù)單元中設(shè)置屬性判定是否在事務(wù)中,如果不在事務(wù)中,我
當(dāng)前文章:系統(tǒng)架構(gòu)師談企業(yè)應(yīng)用架構(gòu)之?dāng)?shù)據(jù)訪問層
文章起源:http://www.dlmjj.cn/article/coojsip.html


咨詢
建站咨詢
