iBATIS In Action:什么是iBATIS(一)
2007-08-19 20:39 by Anders Cui, 15830 閱讀, 49 評(píng)論, 收藏, 編輯在上一章中我們?cè)敿?xì)討論了iBATIS的哲學(xué)觀,以及這個(gè)框架的來(lái)歷。我們也說(shuō)過(guò),iBATIS是一個(gè)混合式的解決方案(hybrid solution),借鑒了多種操作關(guān)系數(shù)據(jù)庫(kù)的方法的理念。那么iBATIS到底是什么呢?這一章就來(lái)回答這個(gè)問(wèn)題。
iBATIS是一種data mapper。Martin Fowler在他的《Patterns of Enterprise Application Architecture》一書(shū)中是這樣描述Data Mapper的:
一個(gè)映射層,在對(duì)象和數(shù)據(jù)庫(kù)間傳遞數(shù)據(jù),并保持兩者與映射層本身相獨(dú)立。.
注:Mapper是在兩個(gè)獨(dú)立對(duì)象間建立通信關(guān)系的一種對(duì)象。
Martin很好地區(qū)分了數(shù)據(jù)映射(Data Mapping)和元數(shù)據(jù)映射(Metadata Mapping),后者正是O/RM工具的依據(jù),這種工具將數(shù)據(jù)庫(kù)的表和列映射到應(yīng)用程序中的類和字段(field),也就是說(shuō)它將數(shù)據(jù)庫(kù)的元數(shù)據(jù)映射到類的元數(shù)據(jù)。圖2.1顯示了類和數(shù)據(jù)庫(kù)表的O/R 映射的情形。在這種情況下,類的每個(gè)字段映射到了表中的一個(gè)相應(yīng)的列。
譯注:在C#中通常在類的屬性(Property)與表的列間進(jìn)行映射。
iBATIS則與之不同,它不是直接在類與數(shù)據(jù)表或字段與列之間進(jìn)行關(guān)聯(lián),而是把SQL語(yǔ)句的參數(shù)(parameter)和返回結(jié)果(result)映射至類。在本書(shū)的剩余部分您將看到,iBATIS是處于類和數(shù)據(jù)表之間的一個(gè)中間層,這使得它在類和數(shù)據(jù)表之間進(jìn)行映射時(shí)更加靈活,而不需要數(shù)據(jù)庫(kù)模型或?qū)ο竽P停?/span>object model)的任何修改。我們所說(shuō)的中間層實(shí)際上就是SQL,它使得iBATIS能夠更好地分離數(shù)據(jù)庫(kù)和對(duì)象模型的設(shè)計(jì),這樣就相對(duì)減少了兩者間的耦合。圖2.2說(shuō)明了iBATIS如何使用SQL映射數(shù)據(jù)。
從圖2.2可以看到,iBATIS的映射層正是SQL。您只管寫您的SQL,iBATIS會(huì)為您處理類的屬性和數(shù)據(jù)表的列之間的映射。有鑒于此,同時(shí)也為了消除與其它各種映射方式引起的混淆,iBATIS團(tuán)隊(duì)通常稱這種Data Mapper為SQL Mapper。
2.1 SQL 映射
任何SQL語(yǔ)句都可看作是一組輸入和輸出。輸入的值是參數(shù)(parameter),通常出現(xiàn)在WHERE子句中。輸出的值則是出現(xiàn)在SELECT子句中的列。圖2.3描述了這種觀點(diǎn)。
這種方式的優(yōu)勢(shì)在于SQL語(yǔ)句給開(kāi)發(fā)人員帶來(lái)了很大的靈活性。我們可以輕松地操作數(shù)據(jù)使之與對(duì)象模型匹配而無(wú)需修改后臺(tái)的數(shù)據(jù)庫(kù)設(shè)計(jì)。此外,開(kāi)發(fā)人員可以使用內(nèi)置的數(shù)據(jù)庫(kù)函數(shù)或存儲(chǔ)過(guò)程來(lái)返回多個(gè)不同的表或結(jié)果,SQL的強(qiáng)大能力變得信手拈來(lái)。
iBATIS使用一個(gè)簡(jiǎn)單的XML描述文件來(lái)映射SQL語(yǔ)句的輸入和輸出。列表2.1顯示了一個(gè)描述文件的示例。
此處我們可以看到一條SELECT SQL語(yǔ)句,它返回的是地址信息。根據(jù)<select>元素我們可以了解它接受一個(gè)整型數(shù)作為參數(shù),也就是WHERE子句中標(biāo)記為#id#的部分。我們也可了解結(jié)果為Address類型的一個(gè)實(shí)例,這里假定Address類包含了與SELECT子句中每一列的別名名稱相同的屬性。例如,別名為id的列將會(huì)映射至Address類的id屬性。信不信由你,這就是映射一條接受整型參數(shù)、返回Address對(duì)象的SQL語(yǔ)句所需的全部了。執(zhí)行這條語(yǔ)句使用的Java代碼是:
Address address = (Address) sqlMap.queryForObject("getAddress", new Integer(5));
我們的SQL映射方式可移植性很強(qiáng),可以應(yīng)用到任何特性完整的編程語(yǔ)言。比如,使用iBATIS.NET的C#代碼為:
Address address = (Address) sqlMap.QueryForObject("getAddress", 5);
當(dāng)然,關(guān)于映射還有更多的高級(jí)選項(xiàng),特別是返回結(jié)果(result)相關(guān)的,我們將會(huì)在第二部分(iBATIS基礎(chǔ))進(jìn)行討論?,F(xiàn)在,理解iBATIS的特性和優(yōu)點(diǎn)以及其工作原理更為重要。
2.2 工作原理
最根本的一點(diǎn)是,iBATIS可用于替代ADO.NET。ADO.NET提供的API非常強(qiáng)大,卻繁復(fù)而冗長(zhǎng)??紤]下面的ADO.NET代碼:
{
Employee employee = null;
string connString = "Server=(local);Database=iBatisInAction;Uid=sa;Pwd=sa;";
// Our SQL is buried here.
string sql = "SELECT * FROM EMPLOYEE WHERE EMPLOYEE_NUMBER = @EmployeeNumber";
SqlConnection conn = null;
SqlCommand command = null;
SqlDataReader reader = null;
try
{
conn = new SqlConnection(connString);
conn.Open();
command = new SqlCommand(sql, conn);
command.Parameters.Add("@EmployeeNumber", SqlDbType.Int).Value = number;
reader = command.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
employee = new Employee();
employee.Id = Convert.ToInt32(reader["ID"]);
employee.EmployeeNumber = Convert.ToInt32(reader["EMPLOYEE_NUMBER"]);
employee.FirstName = reader["FIRST_NAME"] as string;
employee.LastName = reader["LAST_NAME"] as string;
employee.Title = reader["TITLE"] as string;
}
}
finally
{
try
{
if (reader != null)
{
reader.Close();
}
}
finally
{
if (conn != null)
{
conn.Close();
}
}
}
return employee;
}
不難看出ADO.NET API的復(fù)雜。每一行都是必須的,因而無(wú)法精簡(jiǎn)代碼。最好也只能做到將一些公用代碼提取到工具方法中,尤其是在釋放資源的那部分代碼。
譯注:微軟的SqlHelper類就是這樣的工具類。
實(shí)際上,iBATIS會(huì)以近似于ADO.NET的方式運(yùn)行。iBATIS會(huì)連接到數(shù)據(jù)庫(kù),設(shè)置參數(shù),執(zhí)行語(yǔ)句,獲取結(jié)果,然后關(guān)閉和釋放資源。但您需要寫的代碼則顯著減少。代碼清單2.3顯示了在iBATIS中執(zhí)行相同語(yǔ)句所需的代碼。
SELECT
ID AS Id,
EMPLOYEE_NUMBER AS EmployeeNumber,
FIRST_NAME AS FirstName,
LAST_NAME AS LastName,
TITLE AS Title
From Employee
Where EMPLOYEE_NUMBER = #EmployeeNumber#
</select>
兩者實(shí)在是沒(méi)可比性。iBATIS的代碼要簡(jiǎn)練得多,而且也更容易維護(hù)。我們將在本章的后面部分討論iBATIS的更多好處。不過(guò)現(xiàn)在,您也許想知道如何在代碼中執(zhí)行它。就如在您在前面的例子中所見(jiàn)的,它只需一行簡(jiǎn)單的代碼:
再不需要其它的了。這一行代碼會(huì)執(zhí)行SQL語(yǔ)句,設(shè)置參數(shù)值,返回一個(gè)C#對(duì)象作為結(jié)果。SQL被很好地封裝在了XML文件中。iBATIS會(huì)管理所有藏在“幕后”的資源,其結(jié)果則于清單2.2中的ADO.NET代碼相同。
上述方式引出一個(gè)問(wèn)題,iBATIS會(huì)以相同的方式工作于所有系統(tǒng)?它是否特別適合于某些特定類型的應(yīng)用?下面幾個(gè)小節(jié)將回答這個(gè)問(wèn)題,先看看iBATIS是多么適合小型應(yīng)用程序。
2.2.1 在小型、簡(jiǎn)單的系統(tǒng)中使用iBATIS
小的應(yīng)用程序通常只使用單個(gè)數(shù)據(jù)庫(kù),用戶界面和領(lǐng)域模型(domain model)也較為簡(jiǎn)單。業(yè)務(wù)邏輯非?;A(chǔ),甚至在一些簡(jiǎn)單的CRUD(Create,Read,Update,Delete)應(yīng)用程序中根本不存在。有三種原因使得iBATIS很適合于這種小型的應(yīng)用程序。
首先,iBATIS本身就是小巧而簡(jiǎn)單的。它不需要服務(wù)器和任何其它中間件(middleware)。不需要任何額外機(jī)制的支持。iBATIS不依賴于其它第三方組件。一份最小的iBATIS安裝只需引用一個(gè)dll文件和244KB的磁盤空間。除了SQL映射文件,再不需要其它安裝,因此只需幾分鐘時(shí)間,您就可以擁有一個(gè)可以使用的數(shù)據(jù)持久層了。
其次,iBATIS不會(huì)影響到既有的應(yīng)用程序或數(shù)據(jù)庫(kù)的設(shè)計(jì)。因此,如果您有一個(gè)小型應(yīng)用程序,已經(jīng)有了部分實(shí)現(xiàn),甚至已經(jīng)發(fā)布了,都可以使用iBATIS對(duì)持久層進(jìn)行重構(gòu)。因?yàn)?/span>iBATIS的簡(jiǎn)單,它不會(huì)使您的程序結(jié)構(gòu)過(guò)于復(fù)雜,這一點(diǎn)O/RM工具或代碼生成器未必能夠保證,因?yàn)樗鼈兛偸腔趯?duì)應(yīng)用程序或數(shù)據(jù)庫(kù)所作的某種假設(shè)。
最后,如果您已經(jīng)經(jīng)歷過(guò)一段時(shí)間的軟件開(kāi)發(fā),那么應(yīng)該同意,小的軟件系統(tǒng)成長(zhǎng)為大的系統(tǒng)幾乎是不可避免的。所有成功的軟件都有著成長(zhǎng)的趨勢(shì)。值得慶幸的是,iBATIS也適合于大型軟件系統(tǒng),它可以滿足企業(yè)級(jí)應(yīng)用程序的需要。
2.2.2 在大型的,企業(yè)級(jí)系統(tǒng)中使用iBATIS
iBATIS是為企業(yè)級(jí)應(yīng)用程序而設(shè)計(jì)的。首先要說(shuō)的是,iBATIS在此領(lǐng)域相比于其它解決方案擁有諸多優(yōu)勢(shì)。從大規(guī)模(large-scale)的應(yīng)用程序到企業(yè)級(jí)系統(tǒng),iBATIS的原創(chuàng)者都曾有機(jī)會(huì)參與過(guò),這些系統(tǒng)通常涉及多個(gè)數(shù)據(jù)庫(kù),而他卻都無(wú)法對(duì)其進(jìn)行管理和控制。在第一章中我們討論了各種類型的數(shù)據(jù)庫(kù),包括企業(yè)數(shù)據(jù)庫(kù),proprietary數(shù)據(jù)庫(kù)和遺留數(shù)據(jù)庫(kù)。我們?cè)诰帉?/span>iBATIS時(shí)很大程度上是為了能夠處理這一類的數(shù)據(jù)庫(kù)。最終,iBATIS擁有大量特性,使得它很適合于企業(yè)級(jí)系統(tǒng)。
首先的一點(diǎn)已在前面提到過(guò),但是它如此重要,值得再次聲明:iBATIS不對(duì)您的數(shù)據(jù)庫(kù)或?qū)ο竽P妥魅魏渭僭O(shè)。不管這兩種設(shè)計(jì)間是如何得不匹配,iBATIS總會(huì)有效。此外,iBATIS不對(duì)您的企業(yè)系統(tǒng)的架構(gòu)作任何假設(shè)。不論您的數(shù)據(jù)庫(kù)是按業(yè)務(wù)功能縱向劃分,還是從技術(shù)上橫向劃分,iBATIS都能夠?qū)⑺c您的OO應(yīng)用程序有效地整合起來(lái)。
其次,iBATIS可以有效地處理很大規(guī)模的數(shù)據(jù)。iBATIS支持像row handler這樣的特性,可以對(duì)大量記錄進(jìn)行批處理。它還支持獲取某個(gè)范圍內(nèi)的數(shù)據(jù),這樣我們可以僅僅獲取當(dāng)前必須的數(shù)據(jù)。如果您有10000條記錄,但是只需要第500-600條記錄,iBATIS可以輕松實(shí)現(xiàn)。iBATIS支持driver hint,從而可以高效地完成這些操作。
最后,iBATIS允許將對(duì)象以多種方式映射至數(shù)據(jù)庫(kù)。企業(yè)應(yīng)用系統(tǒng)的功能以單一模式實(shí)現(xiàn)的情況是很少的。很多企業(yè)級(jí)系統(tǒng)需要在白天進(jìn)行事務(wù)處理,而在夜間進(jìn)行數(shù)據(jù)批處理操作。iBATIS允許以多種方式映射,保證了每種業(yè)務(wù)處理都能以盡可能高效的方式進(jìn)行。iBATIS還支持多種訪問(wèn)策略。您可以選擇都某些數(shù)據(jù)進(jìn)行延遲加載,通過(guò)SQL來(lái)加載那些復(fù)雜屬性,避免帶來(lái)嚴(yán)重的性能問(wèn)題。
看到這里,您也許覺(jué)得這很像一個(gè)促銷廣告。那何不說(shuō)說(shuō)為什么需要iBATIS呢?我們將在2.5節(jié)中做更詳細(xì)的說(shuō)明。為公平起見(jiàn),我們會(huì)在稍后的2.4節(jié)中討論一些您不需要使用iBATIS的情況。
2.3 為什么要使用iBATIS?
2.3.1 簡(jiǎn)單
iBATIS是當(dāng)前公認(rèn)的最簡(jiǎn)單的持久層框架之一。簡(jiǎn)單是iBATIS團(tuán)隊(duì)設(shè)計(jì)目標(biāo)的核心,其重要性幾乎要超過(guò)其它任何方面。它的簡(jiǎn)單是通過(guò)它構(gòu)建的基礎(chǔ)來(lái)達(dá)到的:ADO.NET和SQL。iBATIS對(duì)于.NET程序員來(lái)說(shuō)是簡(jiǎn)單的,因?yàn)樗褂闷饋?lái)像ADO.NET,只不過(guò)代碼少了許多。幾乎所有您對(duì)ADO.NET的了解都適用于iBATIS,我們可以把iBATIS視作以XML格式描述的ADO.NET代碼。前面說(shuō)過(guò),iBATIS包含很多ADO.NET所不具備的架構(gòu)上的優(yōu)點(diǎn),我們會(huì)在后面討論。iBATIS對(duì)于數(shù)據(jù)庫(kù)管理員和SQL開(kāi)發(fā)人員來(lái)說(shuō)也是簡(jiǎn)單的。幾乎任何擁有SQL編程經(jīng)驗(yàn)的開(kāi)發(fā)人員都很容易理解iBATIS的配置文件。
2.3.2 生產(chǎn)力
一個(gè)好框架要考慮的第一要旨是使開(kāi)發(fā)人員更具生產(chǎn)力。通??蚣軙?huì)處理一些通用任務(wù),減少重復(fù)性(boilerplate)的編碼,解決復(fù)雜的架構(gòu)問(wèn)題。在一項(xiàng)由意大利Java用戶組進(jìn)行的案例研究(http://www./vqwiki/jsp/Wiki?IBatisCaseStudy)中,Fabrizio Gianneschi發(fā)現(xiàn)iBATIS可以減少持久層的代碼達(dá)62%之多。SQL依然需要手工編寫,但如您先前所見(jiàn),SQL不是問(wèn)題——不管您是使用JDBC還是ADO.NET。
譯注:這項(xiàng)研究將一個(gè)項(xiàng)目由原來(lái)的JDBC轉(zhuǎn)換為iBATIS代碼,得出了上述結(jié)論。但對(duì)于ADO.NET是何結(jié)果就不得而知了,但相信也能減少大量代碼。
2.3.3 性能
性能這個(gè)主題能夠引發(fā)框架作者、用戶甚至商用軟件商的爭(zhēng)論。事實(shí)上,在較低層次上來(lái)看,任何框架都會(huì)存在或多或少的性能損失。一般地,比較一下手工編寫的ADO.NET和iBATIS,在一個(gè)for循環(huán)中遍歷一百萬(wàn)次,會(huì)發(fā)現(xiàn)ADO.NET更具優(yōu)勢(shì)。幸運(yùn)的是,在當(dāng)今應(yīng)用程序開(kāi)發(fā)中,這并不是關(guān)鍵的性能點(diǎn)。更為重要的是,如何從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù),何時(shí)獲取它,以及獲取的頻率。例如,從數(shù)據(jù)庫(kù)中獲取分頁(yè)后的列表數(shù)據(jù)能顯著地提升應(yīng)用程序的性能,因?yàn)檫@樣就避免了一次加載過(guò)多的數(shù)據(jù)。類似的,使用像延遲加載(lazy load)這樣的特性可以避免在給定的用例下加載不必要的數(shù)據(jù)。另一方面,如果我們確定需要加載復(fù)雜的對(duì)象屬性,而這些屬性來(lái)自于多個(gè)數(shù)據(jù)表,那么使用單條SQL來(lái)加載數(shù)據(jù)也可以極大地改善性能。iBATIS提供了多種性能優(yōu)化策略,我們將在后面討論。現(xiàn)在,我們要知道,通常要以簡(jiǎn)單的方式來(lái)配置iBATIS,但它的性能會(huì)像ADO.NET一樣好,甚至更好。另一個(gè)需要考慮的地方是,并不是所有的ADO.NET代碼都能編寫得很好。ADO.NET是一個(gè)復(fù)雜的API,要想正確使用需要注意很多地方。不幸的是,很多ADO.NET代碼編寫的不好,導(dǎo)致其性能甚至不如iBATIS。
2.3.4 分離關(guān)注點(diǎn)
在典型的ADO.NET代碼中,有時(shí)會(huì)看到數(shù)據(jù)庫(kù)資源如連接、結(jié)果集散布在程序各個(gè)層中。在一些糟糕的程序中,我們會(huì)看到數(shù)據(jù)庫(kù)連接、語(yǔ)句出現(xiàn)在表現(xiàn)層。這實(shí)在是惡夢(mèng)般的經(jīng)歷。在第一章中我們?cè)懻撨^(guò)應(yīng)用程序分層的重要性。我們看到了應(yīng)用程序如何在較高層次上分層,持久層是如何處于中間層次的。iBATIS提供了此種分層的支持,它會(huì)管理所有數(shù)據(jù)持久相關(guān)的資源,如數(shù)據(jù)庫(kù)連接,語(yǔ)句和結(jié)果集等。它提供了數(shù)據(jù)庫(kù)無(wú)關(guān)的接口和API,幫助應(yīng)用程序中的其它層能夠與任何數(shù)據(jù)持久相關(guān)的資源保持獨(dú)立。使用iBATIS,我們面對(duì)的是真正的對(duì)象,而不是任意的結(jié)果集。iBATIS使保持良好的分層變成一件容易的事。
2.3.5 分工
有的數(shù)據(jù)庫(kù)管理員很是珍愛(ài)他們的數(shù)據(jù)庫(kù),以至于不愿意其它人為其編寫SQL。還有的人很擅長(zhǎng)編寫SQL,其他人都希望由他們來(lái)寫SQL。不管處于何種情況,我們總是應(yīng)該好好利用團(tuán)隊(duì)成員的優(yōu)勢(shì)。如果團(tuán)隊(duì)里有人特別擅長(zhǎng)編寫SQL,而不太喜歡編寫C#代碼,那就讓他們盡情地寫SQL吧。iBATIS使之成為可能。因?yàn)?/span>SQL語(yǔ)句和應(yīng)用程序代碼分離得非常清楚,SQL開(kāi)發(fā)人員可以按其固有的方式進(jìn)行開(kāi)發(fā),而不用擔(dān)心什么字符串的拼接。即使有開(kāi)發(fā)人員同時(shí)開(kāi)發(fā)C#代碼和SQL,如果DBA想優(yōu)化數(shù)據(jù)庫(kù)的性能,只要說(shuō)“讓我看看SQL”。如果使用ADO.NET就沒(méi)這么簡(jiǎn)單了,因?yàn)?/span>SQL往往包含在一連串的字符串拼接中,或者是由遍歷和條件動(dòng)態(tài)動(dòng)態(tài)生成。使用O/RM會(huì)更糟糕,我們必須運(yùn)行程序,然后在日志中輸出語(yǔ)句,即使找到了,也不能做任何事情。iBATIS使得任何人都可以自由地開(kāi)發(fā)、查看、修改SQL語(yǔ)句。
2.3.6 可移植性:Java,.NET以及其它
iBATIS可移植性是很強(qiáng)的。這得益于其相對(duì)簡(jiǎn)單的設(shè)計(jì),它可以實(shí)現(xiàn)于幾乎任何語(yǔ)言和平臺(tái)上。在編寫本書(shū)的時(shí)候,iBATIS支持三種最流行的開(kāi)發(fā)平臺(tái):Java,Ruby和C#。
在當(dāng)前配置文件還不是完全平臺(tái)兼容的,但我們已有計(jì)劃向這個(gè)目標(biāo)靠近。更為重要的是,其概念和方式是可移植性很強(qiáng)的。這樣我們所有應(yīng)用程序的設(shè)計(jì)可以保持一致。對(duì)于語(yǔ)言和應(yīng)用程序的類型來(lái)說(shuō),iBATIS比任何其它框架支持得都多。如果在您的程序中一致性非常重要,那么iBATIS將是很好的選擇。
2.3.7 開(kāi)源和可信度
前面我們說(shuō)這一節(jié)是“促銷廣告”。事實(shí)上,iBATIS是免費(fèi)的,開(kāi)源的軟件。無(wú)論您使用與否,我們不會(huì)從中獲得任何收益。您已經(jīng)購(gòu)買了這本書(shū),這就是我們所“賺”的錢了。開(kāi)源軟件最大的優(yōu)勢(shì)之一是可信。我們沒(méi)有任何理由扭曲事實(shí)或者欺騙您。坦率地說(shuō),iBATIS不是所有問(wèn)題的最佳解決方案。下面我們來(lái)點(diǎn)商用軟件文檔中絕少出現(xiàn)的內(nèi)容,討論一下何種情況下不必使用iBATIS,給出一些其它可行的方案。
2.4 何時(shí)不用iBATIS
每一種框架都建立在規(guī)則和約束之上。較低層次的框架如ADO.NET提供了靈活、完整的特性,卻更難使用。較高層次的框架如O/RM工具非常易用,減少了很多工作量,但它們建立更多的假設(shè)和約束之上,使得它們不能應(yīng)用于更多的應(yīng)用程序。
iBATIS是一個(gè)中等層次的框架。它較ADO.NET要高,又比O/RM工具要低。這樣iBATIS實(shí)際上處于一個(gè)獨(dú)特的位置,它有自己適用的范圍。在前面幾節(jié)中,我們討論了iBATIS為何可用于各種類型的應(yīng)用程序,包括小型的,富客戶端的,大型的,企業(yè)級(jí)的以及Web應(yīng)用程序——還有其它處于中間層次的應(yīng)用程序。那么何時(shí)iBATIS不適合使用呢?下面幾個(gè)小節(jié)中我們會(huì)詳細(xì)描述這樣的幾種情況,也會(huì)推薦一些可選的方案。
2.4.1 如果您擁有完全的控制權(quán)…直至永遠(yuǎn)
如果您獲得保證,可以完全地控制應(yīng)用程序和數(shù)據(jù)庫(kù)的設(shè)計(jì),那您實(shí)在是太幸運(yùn)了。不過(guò)這在企業(yè)環(huán)境或核心競(jìng)爭(zhēng)力不在軟件開(kāi)發(fā)方面的業(yè)務(wù)中并不多見(jiàn)。但是,如果您在一家軟件公司工作,開(kāi)發(fā)受保護(hù)的產(chǎn)品,并對(duì)其有著完全的控制權(quán),那么可能就是這種情況。
如果您擁有完全的控制權(quán),那么就有足夠的理由使用O/RM工具,如NHibernate。您可以充分利用O/RM帶來(lái)的設(shè)計(jì)上的好處和開(kāi)發(fā)效率的提高。這樣也許和一個(gè)企業(yè)數(shù)據(jù)庫(kù)組或要集成的遺留系統(tǒng)不存在任何沖突。此外,數(shù)據(jù)庫(kù)可能和應(yīng)用程序部署在一起,這樣的數(shù)據(jù)庫(kù)屬于應(yīng)用程序數(shù)據(jù)庫(kù)(見(jiàn)第1章)。使用Hibernate的項(xiàng)目的一個(gè)好例子是Atlassian的JIRA。他們提供了問(wèn)題跟蹤軟件作為產(chǎn)品,他們對(duì)其有完全的控制。
一定要考慮應(yīng)用程序未來(lái)會(huì)有何變化。如果有可能失去對(duì)數(shù)據(jù)庫(kù)的控制權(quán),那么就該仔細(xì)考慮它對(duì)您的持久層策略帶來(lái)的影響。
2.4.2 如果您的程序中SQL完全是動(dòng)態(tài)生成的
如果您的程序的核心功能是SQL的動(dòng)態(tài)生成,那么iBATIS是錯(cuò)誤的選擇。iBATIS有著很強(qiáng)大的動(dòng)態(tài)SQL特性,支持高級(jí)查詢,甚至是一些動(dòng)態(tài)的更新功能。但如果程序中的每條語(yǔ)句都是動(dòng)態(tài)生成的,那么您最好還是使用原生的ADO.NET,或者構(gòu)建自己的框架。
iBATIS的強(qiáng)大很大程度上體現(xiàn)在允許開(kāi)發(fā)人員自由地手工編寫SQL,直接操作SQL。如果大部分SQL都是動(dòng)態(tài)生成的,那么這個(gè)優(yōu)勢(shì)無(wú)疑就喪失掉了。
2.4.3 如果您不是使用關(guān)系型數(shù)據(jù)庫(kù)
當(dāng)前已經(jīng)有可用于非關(guān)系型數(shù)據(jù)庫(kù)的ADO.NET Provider了,如針對(duì)文本文件的,MS Excel的,XML的,還有其它類型的數(shù)據(jù)存儲(chǔ)。盡管已經(jīng)有人成功地將其應(yīng)用在iBATIS中,對(duì)于大多數(shù)用戶,我們還是不推薦這樣使用。
iBATIS不會(huì)對(duì)您的環(huán)境做出很多假設(shè)。但它仍然希望您使用的是一款真正的關(guān)系型數(shù)據(jù)庫(kù),同時(shí)支持事務(wù)和相對(duì)標(biāo)準(zhǔn)的SQL及存儲(chǔ)過(guò)程。即使是一些知名的數(shù)據(jù)庫(kù)也會(huì)有不支持關(guān)系型數(shù)據(jù)庫(kù)關(guān)鍵特性的情況。MySQL的早期版本不支持事務(wù),因此iBATIS用起來(lái)就不太好。好在現(xiàn)在的MySQL已經(jīng)支持事務(wù),還提供了不錯(cuò)的ADO.NET Provider。
譯注:看看這里,ADO.NET支持多少類型的數(shù)據(jù)存儲(chǔ)。
如果您不是使用真正的關(guān)系型數(shù)據(jù)庫(kù),我們建議您使用原生的ADO.NET甚至是更低層次的文件I/O API。
2.4.4 如果iBATIS不能奏效
iBATIS社區(qū)的需求在不斷增加,所以有很多特性正在開(kāi)發(fā)過(guò)程中。但是iBATIS有自己的方向和設(shè)計(jì)宗旨,這有時(shí)可能會(huì)發(fā)生沖突。人們?cè)陂_(kāi)發(fā)過(guò)程中可能會(huì)做一些驚人的事情,在有些情況下,iBATIS不能奏效,因?yàn)樾枨筇^(guò)復(fù)雜。盡管我們可以添加功能來(lái)滿足這些需求,卻會(huì)帶來(lái)極大的復(fù)雜性或者超出了iBATIS框架的范圍之外。最終,我們決定不去改變框架。為滿足這些需求,我們會(huì)設(shè)法提供可插入(pluggable)的接口,這樣您就可以擴(kuò)展iBATIS來(lái)滿足幾乎任何需要。有時(shí)情況很簡(jiǎn)單,它就是不能使用。這時(shí),最好去選擇更好的解決方案,而不是對(duì)iBATIS(任何框架都是如此)勉為其難。
關(guān)于Why和Why not就到此為止吧,下一次我們來(lái)看一個(gè)簡(jiǎn)單的例子。
譯
注:這一部分就是不停地為iBATIS美言,像我很喜歡它的,都有點(diǎn)不好意思了??陀^地說(shuō),iBATIS很不錯(cuò),適用的程序類型很廣泛,但這也導(dǎo)致了它在
某些時(shí)候不如一些更“專一”的框架好用。據(jù)我所知,在Java社區(qū),iBATIS的使用率比起Hibernate來(lái)還是有不小的差距。它的SQL是它的靈
活和強(qiáng)大之處,維護(hù)起來(lái)卻是個(gè)問(wèn)題。但我感覺(jué)如果你要使用ADO.NET,一般情況下iBATIS會(huì)給你帶來(lái)不小的幫助??梢钥纯碢etshop里面的數(shù)
據(jù)持久層,它維護(hù)起來(lái)要比iBATIS難很多。
下載本文相關(guān)代碼。 
第一次想這么嚴(yán)格地翻譯一些東西,很多地方比較生硬,大家有何建議,請(qǐng)?zhí)嵋幌?,幫我改進(jìn)下 :)

 
                         
                                
 
                                





 
                        

