鳳凰涅槃:從 iBatis 到 MyBatis

來源:互聯網
上載者:User

MyBatis 簡明學習教程

簡介: 本文主要講述了 iBatis 2.x 和 MyBatis 3.0.x 的區別,以及從 iBatis 向 MyBatis 移植時需要注意的地方。通過對本文的學習,讀者基本能夠瞭解 MyBatis 有哪些方面的改進,並能夠順利使用 MyBatis 進行開發。本文更適合有 iBatis 基礎的開發人員閱讀。



從 iBatis 到 MyBatis,你準備好了嗎?

對於從事 Java EE 的開發人員來說,iBatis 是一個再熟悉不過的持久層架構了,在 Hibernate、JPA 這樣的一站式對象 / 關係映射(O/R Mapping)解決方案盛行之前,iBaits 基本是持久層架構的不二選擇。即使在持久層架構層出不窮的今天,iBatis 憑藉著易學易用、輕巧靈活等特點,也仍然擁有一席之地。尤其對於擅長 SQL 的開發人員來說,iBatis 對 SQL 和預存程序的直接支援能夠讓他們在獲得 iBatis 封裝優勢的同時而不喪失 SQL 調優的手段,這是 Hibernate/JPA
所無法比擬的。具體而言,使用 iBatis 架構的主要優勢主要體現在如下幾個方面:

首先,iBatis 封裝了絕大多數的 JDBC 樣板代碼,使得開發人員只需關注 SQL 本身,而不需要花費精力去處理例如註冊驅動,建立 Connection,以及確保關閉 Connection 這樣繁雜的代碼。

其次,iBatis 可以算是在所有主流的持久層架構中學習成本最低,最容易上手和掌握的架構。雖說其他持久層架構也號稱門檻低,容易上手,但是等到你真正使用時會發現,要想掌握並用好它是一件非常困難的事。在工作中我需要經常參與面試,我曾聽到過很多位應聘者描述,他們所在的項目在技術選型時選擇 Hibernate,後來發現難以駕馭,不得不將代碼用 JDBC 或者 iBatis 改寫。

iBatis 自從在 Apache 軟體基金會網站上發布至今,和他的明星兄弟們(Http Server,Tomcat,Struts,Maven,Ant 等等)一起接受者萬千 Java 開發人員的敬仰。然而在今年六月中旬,幾乎是發布 3.0 版本的同時,iBatis 首頁上的一則 “Apache iBATIS has been retired” 的聲明在社區引起了一陣不小的波瀾。在 Apache 寄居六年之後,iBatis 將代碼託管到 Google Code。在聲明中給出的主要理由是,和 Apache 相比,Google
Code 更有利於開發人員的協同工作,也更能適應快速發布。於此同時,iBatis 更名為 MyBatis。

從 iBatis 到 MyBatis,不只是名稱上的變化,MyBatis 提供了更為強大的功能,同時並沒有損失其易用性,相反,在很多地方都藉助於 JDK 的泛型和註解特性進行了簡化。iBatis 確實該退休了,因為一個更為出色的繼任者經過 10 個 Beta 版本的蛻變已然出現在我們的面前。

本文將主要針對 MyBatis 和 iBatis 的變化之處進行討論,以便於讀者順利從 iBatis 向 MyBatis 過渡。

回頁首

由一個 MyBatis 樣本開始

如果讀者接觸過一些常用的 Java EE 架構,應該都知道這些架構需要提供一個全域設定檔,用於指定程式正常運行所需的設定和參數資訊。而針對常用的持久層架構而言(Hibernate、JPA、iBatis 等),則通常需要配置兩類檔案:一類用於指定資料來源、事務屬性以及其他一些參數配置資訊(通常是一個獨立的檔案,可以稱之為全域設定檔);另一類則用於指定資料庫表和程式之間的映射資訊(可能不止一個檔案,我們稱之為對應檔)。MyBatis 也不例外,雖然其中的一部分可以通過註解的形式進行,但是這兩部分內容本身仍是必不可少的。

根據 iBatis 的習慣,我們通常把全域設定檔命名為 sqlMapConfig.xml,檔案名稱本身並沒有要求,在 MyBatis 中,也經常會將該檔案命名為 Configuration.xml (讀完全文後讀者也許會發現,在 iBatis 中經常出現的 “sqlMap” 在 MyBatis 中被逐漸淡化了,除了此處,還比如 iBatis 設定檔的根項目為 <sqlMapConfig>,指定對應檔的元素為 <sqlMap>,以及 SqlMapClient 等等,這個變化正說明,iBatis 僅是以
SQL 映射為核心的架構,而在 MyBatis 中多以 Mapper、Session、Configuration 等其他常用 ORM 架構中的名字代替,體現的無非是兩個方面:首先是為了減少開發人員在切換架構所帶來的學習成本;其次,MyBatis 充分吸收了其他 ORM 架構好的實踐,MyBatis 現在已不僅僅是一個 SQL 映射架構了)。在全域設定檔中可以配置的資訊主要包括如下幾個方面:

  • properties --- 用於提供一系列的索引值對組成的屬性資訊,該屬性資訊可以用於整個設定檔中。
  • settings --- 用於設定 MyBatis 的運行時方式,比如是否啟用消極式載入等。
  • typeAliases --- 為 Java 類型指定別名,可以在 XML 檔案中用別名取代 Java 類的全限定名。
  • typeHandlers --- 在 MyBatis 通過 PreparedStatement 為預留位置設定值,或者從 ResultSet 取出值時,特定類型的類型處理器會被執行。
  • objectFactory --- MyBatis 通過 ObjectFactory 來建立結果對象。可以通過繼承 DefaultObjectFactory 來實現自己的 ObjectFactory 類。
  • plugins --- 用於配置一系列攔截器,用於攔截映射 SQL 陳述式的執行。可以通過實現 Interceptor 介面來實現自己的攔截器。
  • environments --- 用於配置資料來源資訊,包括串連池、事務屬性等。
  • mappers --- 程式中所有用到的 SQL 對應檔都在這裡列出,這些映射 SQL 都被 MyBatis 管理。

上面提及的大多數元素都不是必需的,通常 MyBatis 會為沒有顯式設定的元素提供預設值。一個簡單的全域設定檔樣本如下:

清單 1. 簡單的全域設定檔樣本

 <?xml version="1.0" encoding="UTF-8" ?>  <!--iBatis 和 MyBatis 的全域設定檔使用不同的 DTD 約束,在將應用由 iBatis 升級至 MyBatis 時需要注意(兩者的對應檔 DTD 約束也不相同)-->  <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">  <configuration>  <!-- 配置資料來源相關的資訊 -->  <environments default="demo">  <environment id="demo">  <transactionManager type="JDBC"/>  <dataSource type="POOLED">  <property name="driver" value= … />  <property name="url" value= … />  <property name="username" value="root"/>  <property name="password" value="root"/>  </dataSource>  </environment>  </environments>  <!-- 列出對應檔 -->  <mappers>  <mapper resource="footmark/mybatis/demo/UserInfoMapper.xml"/>  </mappers>  </configuration> 

有了這些資訊,MyBatis 便能夠和資料庫建立串連,並應用給定的串連池資訊和事務屬性。MyBatis 封裝了這些操作,最終暴露一個 SqlSessionFactory 執行個體供開發人員使用,從名字可以看出來,這是一個建立 SqlSession 的工廠類,通過 SqlSession 執行個體,開發人員能夠直接進行商務邏輯的操作,而不需要重複編寫 JDBC 相關的樣板代碼。根據全域設定檔產生 SqlSession 的代碼如下:

 Reader reader = Resources.getResourceAsReader("Configuration.xml");  SqlSessionFactory sqlSessionFactory =  new SqlSessionFactoryBuilder().build(reader);  SqlSession sqlSession = sqlSessionFactory.openSession(); 

可以把上面的三行代碼看做是 MyBatis 建立 SqlSession 的樣板代碼。其中第一行代碼在類路徑上載入設定檔,Resources 是 MyBatis 提供的一個工具類,它用於簡化資源檔的載入,它可以訪問各種路徑的檔案,不過最常用的還是樣本中這種基於類路徑的表示方式。如果讀者對 Hibernate 有所瞭解,一定會發現 MyBatis 不論是使用風格還是類名都和 Hibernate 非常相像,筆者曾今多次在國內外 Java 社區看到有人說 MyBatis 在向 Hibernate/JPA 靠攏。暫且不論這是否屬實,持久化技術在經過一番蓬勃的競爭和發展,最終在社區形成統一的認識並被廣泛接受,這對開發人員而言未必不是一件好事,MyBatis
在這一點上只是向事實上的標準靠近了一步。

在完成全域設定檔,並通過 MyBatis 獲得 SqlSession 對象之後,便可以執行資料訪問操作了。對於 iBatis/MyBatis 而言,要執行的操作其實就是在對應檔中配置的 SQL 陳述式。兩者的配置基本相同,如下所示:

清單 2. 在對應檔中配置 SQL 陳述式

 <?xml version="1.0" encoding="UTF-8" ?>  <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">  <mapper namespace="mybatis.demo.UserInfoMapper">  <select id="selectUser" parameterType="int" resultType="mybatis.demo.UserInfo">  select * from UserInfo where userid =#{userid}  </select>  </mapper> 

在 iBatis 中,namespace 不是必需的,且它的存在沒有實際的意義。在 MyBatis 中,namespace 終於派上用場了,它使得對應檔與介面綁定變得非常自然。關於介面綁定,後面會有篇幅專門描述。使用 SqlSession 執行 SQL 的方式如下:

清單 3. 使用 SqlSession 執行對應檔中配置的 SQL 陳述式

 try  {  UserInfo userinfo = (UserInfo) sqlSession.selectOne  ("mybatis.demo.UserInfoMapper.getUser", 2);  System.out.println(userinfo);  } finally  {  sqlSession.close();  } 

需要注意的是,SqlSession 的使用必需遵守上面的格式,即在 finally 塊中將其關閉。以保證資源得到釋放,防止出現記憶體泄露!

以上就是一個簡單而完整的 MyBatis 程式。其中涉及了全域設定檔,對應檔,構建 SqlSession 對象,執行資料訪問操作等四個步驟。下面將針對除構建 SqlSession 對象之外的三塊內容進行分解。

回頁首

MyBatis 全域設定檔的改變

MyBatis 全域設定檔的各主要元素基本和 iBatis 相同,只是在用法和個別名稱上做了調整。元素的意義就不再描述,下面主要講述針對 iBatis 和 MyBatis 設定檔的主要區別之處。

首先,兩個版本的 DTD 約束不同,MyBatis 的 DTD 檔案已經包含在發布包下的 mybatis-3.0.x.jar 包中。這直接影響到的是,iBatis 設定檔的根項目是 <sqlMapConfig>,而 MyBatis 使用的是 <configuration>。

其次,<settings> 的用法發生了改變,之前的格式為:

清單 4. 在 iBatis 中設定屬性的方式

 <settings props1="value1" props2="value2"… /> 

要設定的屬性直接以索引值對的形式作為 <settings> 的屬性。而在 MyBatis 中調整為略顯複雜但卻更有條理的方式:

清單 5. 在 MyBatis 中設定屬性的方式

 <settings>  <setting name="props1" value="value1"/>  <setting name="props2" value="value2"/> …… </settings> 

另外,之前配置交易管理員和資料來源的方式如下:

清單 6. 在 iBatis 中配置交易管理員和資料來源的方式

 <transactionManager type="JDBC" >  <dataSource type="SIMPLE">  <property name="JDBC.Driver" value="${driver}"/>  <!-- 其他資料來源資訊省略 -->  </dataSource>  </transactionManager> 

在 MyBatis 中調整為如下的方式:

清單 7. 在 MyBatis 中配置交易管理員和資料來源的方式

 <environments default="demo">  <environment id="demo">  <transactionManager type="JDBC"/>  <dataSource type="POOLED">  <property name="JDBC.Driver" value="${driver}"/>  <!-- 其他資料來源資訊省略 -->  </dataSource>  </environment>  </environments> 

通過 <environments> 來進行資料來源管理,主要是為了簡化在多套資料來源配置之間的切換,比如開發和發布使用不同的配置。

最後,在 iBatis 中指定對應檔的方式如下:

清單 8. 在 iBatis 中指定對應檔的方式

 <sqlMap resource=... />  <sqlMap resource=... />  <sqlMap resource=... /> 

在 MyBatis 中調整為如下方式:

清單 9. 在 MyBatis 中指定對應檔的方式

 <mappers>  <mapper resource=... />  <mapper resource=... />  </mappers> 

上面的這些調整,主要出發點其實並不是使得 MyBatis 功能更為強大,而是使配置更為合理,讓開發人員更容易閱讀和理解。

到目前為止,我們主要討論了 XML 形式的全域配置,其實這也不是唯一選擇,MyBatis 還提供了通過代碼來進行配置的方式:

清單 10. 在 MyBatis 中使用代碼進行配置

 DataSource ds = …… // 擷取一個 DataSource  TransactionFactory txFactory = new JdbcTransactionFactory();  Environment env = new Environment("demo", txFactory, ds);  Configuration cfg = new Configuration(env);  cfg.addMapper(UserInfoMapper.class);  SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(cfg); 

結合前面的設定檔,很容易理解這段代碼的意思,故不再贅述。不過,需要注意的是 Configuration 的 addMapper() 方法,該方法的參數通常是一個介面,可以在介面裡面定義若干方法,在方法上使用註解來指定映射的 SQL 陳述式。一個典型的介面定義以及對應的資料存取方法如下:

清單 11. 將映射的 SQL 陳述式與介面中的方法綁定

 // 映射 SQL 綁定介面 public interface UserInfoMapper  {  @Select("select * from userinfo where userid = #{userid}")  public UserInfo getUserInfo(int userid);  }  // 介面綁定對應的資料存取方法 try  {  //UserInfo userinfo = (UserInfo) sqlSession.selectOne  ("mybatis.demo.UserInfoMapper.selectUser", 2);  UserInfoMapper userinfoMapper =  sqlSession.getMapper(UserInfoMapper.class);  UserInfo userinfo = userinfoMapper.getUserInfo(1);  System.out.println(userinfo);  } finally  {  sqlSession.close();  } 

回頁首

MyBatis 對應檔的改變

MyBatis 針對對應檔進行格式調整的地方很多,但大部分僅僅只是名稱上的變化,現代的 IDE 都支援聯想功能,可以很方便的擷取到當前位置可以有哪些元素、哪些屬性等。所以這基本不會給開發人員造成什麼麻煩。

針對對應檔,首先是一系列的屬性名稱的改變,這些僅僅是名稱的改變,用法和含義並沒有發生變化:

  • 和全域設定檔一樣,由於 DTD 約束髮生變化,根項目也由原來的 <sqlMap> 調整為 <mapper>。
  • <select> 等元素的 parameterClass 屬性改為了 parameterType 屬性。
  • <select> 等元素的 resultClasss 屬性改為了 resultType 屬性。
  • <parameterMap> 等元素的 class 屬性改為了 type 屬性。
  • <result> 元素的 columnIndex 屬性被移除了。
  • 嵌套參數由 #value# 改為了 #{value}。
  • <parameter> 等元素的 jdbcType 屬性取值中,原來的 "ORACLECURSOR" 取值改為了現在的 "CURSOR","NUMBER" 取值改為了 "NUMERIC"。

iBatis/MyBatis 對預存程序的支援一直是值得稱道的。之前通過使用 <procedure> 元素進行預存程序的定義,樣本如下:

清單 12. iBatis 中調用預存程序的方式

 <procedure id="getValues" parameterMap="getValuesPM">     { ? = call pkgExample.getValues(p_id => ?) }  </procedure> 

在 MyBatis 中,<proccedure> 元素已經被移除,通過 <select>、<insert> 和 <update> 進行定義:

清單 13. MyBatis 中調用預存程序的方式

 <select id="getValues" parameterMap="getValuesPM" statementType="CALLABLE">     { ? = call pkgExample.getValues(p_id => ?)}  </select> 

如上所示,通過 statementType 屬性將該語句標識為預存程序而非普通 SQL 陳述式。

回頁首

代碼層面的改變

通過前面的樣本可以看出,MyBatis 在編碼中的最大的改變就是將一個最常用的 API 由 SqlMapClient 改為了 SqlSessionFactory。另外,類型處理器介面也由原來的 TypeHandlerCallback 改為了 TypeHandler。最後 DataSourceFactory 也進行了調整,移動到 org.apache.ibatis.datasource 包下,其中的方法也作了微調。總之,代碼層面公開的部分改動較少,不會給開發人員造成較大的移植成本。

回頁首

總結

本文主要描述了從 iBatis 向 MyBatis 移植過程中可能遇到的問題,大部分的變化已經體現在上文中,如果希望從頭開始學習 MyBatis,則建議從頭開始閱讀官方的 user guide 文檔。

參考資料

學習

  • 參考 MyBatis 官方網站,這裡有豐富的學習文檔。

  • 瀏覽 寄放在 Google Code 上的 MyBatis 項目,這裡可以下載源碼、發布包和文檔。
  • 隨時關注 developerWorks
    技術活動和網路廣播。

  • 訪問 developerWorks
    Open source 專區獲得豐富的 how-to 資訊、工具和項目更新以及最受歡迎的文章和教程,協助您用開放源碼技術進行開發,並將它們與 IBM 產品結合使用。

討論

  • 加入 developerWorks 中文社區,developerWorks 社區是一個面向全球 IT 專業人員,可以提供部落格、書籤、wiki、群組、聯絡、共用和協作等社區功能的專業社交網路社區。

  • 加入
    IBM 軟體下載與技術交流群組,參與線上交流。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.