(經典)從Ibatis過度到Mybatis---比較Mybaits較與Ibatis有哪些方面的改進
隨著開發團隊轉投Google Code旗下,ibatis3.x正式更名為Mybatis。那麼mybatis較於ibatis做了哪些方面的突破呢?這裡我總結些:(不一定完整,是本人整理總結的)
1.全域性檔案的配置:
MyBatis 全域性配置檔案的各主要元素基本和 iBatis 相同,只是在用法和個別名稱上做了調整。元素的意義就不再描述,下面主要講述針對 iBatis 和 MyBatis 配置檔案的主要區別之處。
1.1,兩個版本的 DTD 約束不同,MyBatis 的 DTD 檔案已經包含在釋出包下的 mybatis-3.0.x.jar 包中。這直接影響到的是,
<?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 提供的一個工具類,它用於簡化資原始檔的載入,它可以訪問各種路徑的檔案,不過最常用的還是示例中這種基於類路徑的表示方式。(mybatis現在已經沒有SqlMapClient了,使用的則是SqlSession.在原來的基礎上加了像selectMap,selectList,selectOne這樣的方法,使用更方便了。)
1.2,之前ibatis配置事務管理器和資料來源的方式如下:
<transactionManager type="JDBC" >
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="${driver}"/>
<!-- 其他資料來源資訊省略 -->
</dataSource>
</transactionManager>
在 MyBatis 中配置事務管理器和資料來源的方式:
<environments default="demo">
<environment id="demo">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="JDBC.Driver" value="${driver}"/>
<!-- 其他資料來源資訊省略 -->
</dataSource>
</environment>
</environments>
1.3,在 iBatis 中指定對映檔案的方式如下:
<sqlMap resource=... />
<sqlMap resource=... />
<sqlMap resource=... />
在 MyBatis 中指定對映檔案的方式:
<mappers>
<mapper resource=... />
<mapper resource=... />
</mappers>
附:到目前為止,我們主要討論了 XML 形式的全域性配置,其實這也不是唯一選擇,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 語句。
// 對映 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();
}
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 終於派上用場了,它使得對映檔案與介面繫結變得非常自然。Ibatis用的parameterClass在mybatis中已經永不了了,mybatis裡應該使用parameterType。另外resultMap裡面也不能繼續使用了改成了type。
同時資料型別的宣告和ibatis有了很大的差別,ibatis可以像下面這樣寫
insert into M_HEALTHSPECIALYTYPE(FCODE,FCHARGE,FTYPECONTENT,FID,FMARK)
values (#FCODE:VARCHAR2#,#FCHARGE:VARCHAR2#,#FTYPECONTENT:VARCHAR2#,#FID#,#FMARK:VARCHAR2#)
而在mybatis的話一般是這樣弄的:
insert into M_HEALTHSPECIALYTYPE(FCODE,FCHARGE,FTYPECONTENT,FID,FMARK)
values (#{FCODE,jdbcType=VARCHAR},#{FCHARGE,jdbcType=VARCHAR},#{FTYPECONTENT,jdbcType=VARCHAR},#{FID},#{FMARK,jdbcType=VARCHAR})
針對對映檔案,首先是一系列的屬性名稱的改變,這些僅僅是名稱的改變,用法和含義並沒有發生變化:
· 和全域性配置檔案一樣,由於 DTD 約束髮生變化,根元素也由原來的 <sqlMap> 調整為 <mapper>。
· <select> 等元素的 parameterClass 屬性改為了 parameterType 屬性。
· <select> 等元素的 resultClasss 屬性改為了 resultType 屬性。
· <parameterMap> 等元素的 class 屬性改為了 type 屬性。
· <result> 元素的 columnIndex 屬性被移除了。
· 巢狀引數由 #value# 改為了 #{value}。
· <parameter> 等元素的 jdbcType 屬性取值中,原來的 "ORACLECURSOR" 取值改為了現在的 "CURSOR","NUMBER" 取值改為了 "NUMERIC"。
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 物件,執行資料訪問操作等四個步驟。
4.iBatis/MyBatis 對儲存過程的支援.
iBatis 中呼叫儲存過程的方式(通過使用 <procedure> 元素進行儲存過程的定義):
<procedure id="getValues" parameterMap="getValuesPM">
{ ? = call pkgExample.getValues(p_id => ?) }
</procedure>
在 MyBatis 中,<proccedure> 元素已經被移除,通過 <select>、<insert> 和 <update> 進行定義:
<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 包下,其中的方法也作了微調。總之,程式碼層面公開的部分改動較少,不會給開發者造成較大的移植成本。