上篇中說道MyBatis的前身是IBatis演化而來.其實IBatis發展到今天已經有9年的曆史.當然目前最新版本是IBatis 3.0釋出于2009
年7月. 分别演化出不同的Java和.NET版本. 從3.0釋出至今為止尚沒有做下一個版本的更新.官方也并沒提出下一個版本的更新計劃.但這并不妨礙我們去進一步去探究MyBatis For .NET内部工作的原理.
其實在寫這篇MyBatis原理時 剛開始的思路想從MyBatis插入一條記錄過程來探讨MyBatis是如何解析SQL語句并執行一個Entity Object Mapping 到DataTale過程. 下午和一個同僚做了一下交流.他提出一個看法是"你這樣做還是教别人如何去用MyBatis的API.那隻是MyBatis定義的一套規則而不是真正原理." 這句話仿佛提醒了我換一個角度來對MyBatis在設計Mapping時原理重新解析.我們應該從MyBatis實作整個Mapping過程細節泥沼之中跳出來.專注更多細節隻會讓我們離MyBatis設計初衷背離的越遠.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004146233.jpg"></a>
上篇打該從CRUD的操作學會如何簡單使用IBatis架構.可以看到它Mapping工作中核心的對象對應關系不是EntityModel實體對應關系型資料庫中DataTable 而是EntityModel實體隐射SQL Statement.在來回歸到What Exactly IS MyBatis?這個問題上.我們先把這些細節撇開來看一下設計MyBatis的初衷.
MyBatis作為一個獨立的ORM架構.當然它的核心就是DataMApper資料關系之間的映射.當然針對映射層Martin Fowler大叔在他的《Patterns of Enterprise Application Architecture》一書中針對Data Mapper做了一次經典的描述:
一個映射層,在對象和資料庫間傳遞資料,并保持兩者與映射層本身相獨立.
做一張圖來說明DataMapper層次之間關系:
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004155326.png"></a>
Martin Fowler大叔闡述提到兩個特點:
[1]DataMapper Layer是相對Relation DataBase和Entity Model Layer是獨立的
[2]DataMapper主要職能是實作Relation DataBase和Entity Model 之間資料互動.
談到ORM工具.不得不提的是Nhibernate.但是這裡有兩個概念 資料映射[Data Mapping]和中繼資料映射[Metadata Mapping].而中繼資料映射恰恰展現ORM實作的根本依據. 這在Nhibernate中展現很明顯.例如Nhibernate中定義一個EntityModel-Customer類時實作隐射的關聯方式常常是建立指定具體的Customer類字段與對應資料庫DataTAble表Fild之間.也就是說它将資料庫的中繼資料映射到類的中繼資料.資料庫表每個列都與實體類屬性字段建立映射.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004204605.png"></a>
如上看到Nhibernate架構所采取的映射方式.而MyBatis則不同.它不是直接在類與資料表或字段與列之間進行關聯,而是把SQLStatement 語句的參數[parameter]和傳回結果[result]映射至類.其實從圖1就可以看出MyBatis處于資料庫表與實體對象層之間的中間層. 當我們需要修改時大部分工作集中MyBatis中來.而無需修改資料庫表結構和實體對象結構.這種松散耦合.SQL 其實這種核心還是建立在SQL Statement語句來分離資料庫表結構和實體對象之間設計.
那我們要做什麼呢?
我們隻需編寫對應Action操作的對應的SQl 語句, MyBatis的工作則是替代我們去解決資料庫表結構與實體對象之間的映射.其實這種方式在MyBatis團隊内部把DataMapper直覺叫做SQL Mapper.
到這裡你大概明白MyBatis的底層是在做什麼工作了.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004215179.jpg"></a>
到這裡大概預覽MyBatis底層工作原理.來進一步解析SQL Mapper的核心.MyBatis團隊當初在設計這個架構.巧妙采用SQL Statument作為靈活映射載體.任何一個SQL語句都可以看做是資料庫的流入和流出. 輸入的值作為參數[Parameter] 通常出現And/Where條件子句中. 輸出的資料則一般展現Select中指定表字段.列 舉一個例子吧 一條SQL語句:
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004225827.png"></a>
當執行一條查詢語句時查詢資料作為OutPut輸出結果 ,條件後則作為輸入參數Parameter.這種新的角度來看SQL 語句是在我們單一使用時所看不到的.一條平常SQL語句給人耳目一新感覺.這也是MyBatis在設計 一個獨到匠心之處. 這又給我們帶來什麼呢?
作為獨立中間層SQl Mapper為Developer提供足夠的靈活性.而這些相對Nhibernater一站式封裝不可見的底層來說.為DVP開放一個可以靈活操作的視窗.可以在不修改資料庫表結構的前提下輕松地操作資料使之與對象EntityModel模型進行比對. 同時不要忘了SQl語句本身所帶來的強大文法支援.直接可以使用内置的資料庫函數或存儲過程來傳回多個不同的表或結果. 這種直覺的操作不得不說對DVP來說在很具有誘惑性.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004235187.jpg"></a>
在沒有提出ORM這個概念之前.如果要做一次資料通路.MS給我們API中關聯幾個對象SQLConnection、SQlCommand./SQlDataReader等都是不可或缺的.以前我記得還在使用VS2005是Petshop中也能看到SQLHelper的身影.甚至每個人對SQLHelper需要都不一樣.在其中添加通路資料庫功能和擴充也不盡相同.
不知各位是否還記得在02年MS推出C#和.NEt層以PetShop為藍本聲稱以28倍的性能優勢和1/4的代碼量領先于Java.遭到Java社群口水戰,其實這裡我要說什麼呢?JAVA在資料通路如果以JDBC方式也是有一個固定重複的代碼. 對于高品質 業務需求下.不同語言資料通路代碼重複編寫必然會降低開發人員的效率.這時代碼生成器應運而生. 在一定程度上把DVP從重複資料通路工作解放出來. 随着業務需要這種解放依然不夠靈活徹底.而MyBatis則完全可以替代ADO.NET.
類似利用MyBatis插入一條記錄 要做什麼 首先配置Insert時Action執行的SQL語句:
<statements>
<Insert id="InsertCustomer" parameterClass="Customer">
INSERT INTO dbo.Customer
( Customer_Name ,
Customer_Sex ,
Customer_Age ,
Customer_Address ,
SignOn_Data
)
VALUES ( #CustomerName# , #CustomerSex# , #CustomerAge# , #CustomerAddress#,#SignDate# )
</Insert>
<statements>
配置完成後執行擷取到Customer資料隻需簡潔一句:
public int InsertCustomerByTest(Customer getCustomer)
{
//Insert Customer
object getresult= Mapper.Instance().Insert("InsertCustomer", getCustomer);
return Convert.ToInt32(getresult.ToString());
}
這樣一條Cusotmer資料成功插入.相對ADO.NET那套繁瑣通路資料庫過程.MyBatis這種方式你會發現代碼的量顯著減少 但是效果是一樣的.MyiBATIS的代碼要簡練得多 而且也更容易維護.隻需你做好SQL語句映射配置.其他相關"隐藏"資源管理工作則有MyBatis取代了.就想Batis團隊Blog中一句話:"just care what do you want " 隻需關注你所關心的.或是說在這套架構限制下你需要持續維護即可.類似映射關系.以極小代價換取同樣的效果.
<a target="_blank" href="http://blog.51cto.com/attachment/201201/004244311.jpg"></a>
其實每一種架構都建立于規則和限制之上的.而對于低層次的架構類似ADO.NET 雖然提供靈活 完整的API使用. 卻難以使用.但是我們卻無法忽視這種低層次架構所适用範圍. 而較高層次的架構如O/RM工具非常易用,剔除了重複代碼工作量.但我們不能忘了往往這種自動化是建立更多的假設和限制之上.這也導緻有些ORM架構不能完整适用更多的應用程式.這也就某種程度上照成有些ORM架構在解決一些複雜棘手問題之後同樣也留下一切不可逾越的缺陷.當了解一個ORM架構原理後 也應該客觀正視它所具有的優缺點.在合适場景使用才能發揮類似MyBatis ORM架構所帶來高效.
so How To Use Mybatis?先了解MyBatis具有優缺點.
MyBatis架構高于ADO.NET 卻沒有Nhibernater一站式封裝. MyBatis更多展現的是"半自動化"靈活性 這樣就導緻Mybatis就具有自己使用範圍.
[1]不适用SQL的動态生成
MyBatis突出展現中一點就是SQL語句得開發人員自己編寫. 這也是展現MyBAtis”半自動”這個核心特點. 這也是差別Nhibernater頂層對SQL動态生成一個很重要因素.但這也給MyBatis帶來一定限制.
如果應用程式中設計核心SQL是動态生成的.這個時候你就發現MyBatis的表現就極為低效.MyiBATIS有着很強大的動态SQL特性,支援進階查詢,甚至是一些動态的更新功能。但如果程式中的每條語句都是動态生成的,那麼最好還是使用原生的ADO.NET,或者建構自己的架構。MyiBATIS的強大很大程度上展現在允許開發人員自由地手工編寫SQL,直接操作SQL。如果大部分SQL都是動态生成的,那麼這個優勢無疑就喪失掉了
[2]提倡關系型資料庫
其實昨天我還看到MyBatis官方論壇有的DVP把MyBatis使用以原始檔案為基礎的資料管理上 類似XML資料檔案.中使用MyBatis架構.當然也社群中回報不少使用相關問題.從官方團隊回報翻譯過來:MyiBATIS不會對環境做出很多假設。但它仍然希望您使用的是一款真正的關系型資料庫,同時支援事務和相對标準的SQL及存儲過程。即使是一些知名的資料庫也會有不支援關系型資料庫關鍵特性的情況。MySQL的早期版本不支援事務,是以MyiBATIS用起來就不太好.官方明确在3.0提示建議使用關系型資料庫.
[3]MyBatis的性能
性能這個在ORM架構也是一個很重要的因素.但是從一開始我并不對MyBatis的性能有過多的擔心.畢竟把執行SQL權利交給程式員自己.這在很大程度上未性能留有餘步. 其實昨天我看到IBM上對MyBatis原理類庫結構大概用Refector看了一下核心的代碼.其實在映射處理上采用.NEt的反射機制來實作比對.任何架構都會存在或多或少的性能損失。一般地,比較一下手工編寫的ADO.NET和MyiBATIS,在一個for循環中周遊一百萬次,會發現ADO.NET更具優勢。幸運的是,在當今應用程式開發中,這并不是關鍵的性能點。更為重要的是,如何從資料庫中擷取資料,何時擷取它,以及擷取的頻率。例如,從資料庫中擷取分頁後的清單資料能顯著地提升應用程式的性能,因為這樣就避免了一次加載過多的資料。類似的,使用像延遲加載[lazy load]這樣的特性可以避免在給定的用例下加載不必要的資料。另一方面,如果我們确定需要加載複雜的對象屬性,而這些屬性來自于多個資料表,那麼使用單條SQL來加載資料也可以極大地改善性能。iBATIS提供了多種性能優化政策.性能删MyBatis完全能滿足大部分需求.
當然如上隻是提到個人認為需要注意的地方.MyBatis本身是辦ORM 但是依然具有ORM架構的提高生産力,易用,架構上支援分層的特點等.
參考資料:
<a target="_blank" href="http://www.ibm.com/developerworks/cn/java/j-lo-ibatis-principle/index.html">深入分析IBatis架構系統架構和隐射原理</a>
<a target="_blank" href="http://en.wikipedia.org/wiki/MyBatis">Wiki MyBatis Detail</a>
<a target="_blank" href="http://camel.apache.org/mybatis.html">camel.apache.org[Mybatis]</a>
<a target="_blank" href="http://loianegroner.com/2011/02/introduction-to-ibatis-mybatis-an-alternative-to-hibernate-and-jdbc/">introduction-to-ibatis-mybatis-an-alternative-to-hibernate-and-jdbc</a>
本文轉自chenkaiunion 51CTO部落格,原文連結:http://blog.51cto.com/chenkai/763672