相對(duì)Hibernate和Apache OJB 等“一站式”ORM解決方案而言,ibatis 是一種“半

自動(dòng)化”的ORM實(shí)現(xiàn)。

以前ORM的框架(hibernate,ojb)的局限:

1. 系統(tǒng)的部分或全部數(shù)據(jù)來(lái)自現(xiàn)有數(shù)據(jù)庫(kù),處于安全考慮,只對(duì)開(kāi)發(fā)團(tuán)隊(duì)提供幾條Select SQL(或存儲(chǔ)過(guò)程)以獲取所需數(shù)據(jù),具體的表結(jié)構(gòu)不予公開(kāi)。

2. 開(kāi)發(fā)規(guī)范中要求,所有牽涉到業(yè)務(wù)邏輯部分的數(shù)據(jù)庫(kù)操作,必須在數(shù)據(jù)庫(kù)層由存儲(chǔ)過(guò)程實(shí)現(xiàn)(就筆者工作所面向的金融行業(yè)而言,工商銀行、中國(guó)銀行、交通銀行,都在開(kāi)發(fā)規(guī)范中嚴(yán)格指定)

3. 系統(tǒng)數(shù)據(jù)處理量巨大,性能要求極為苛刻,這往往意味著我們必須通過(guò)經(jīng)過(guò)高度優(yōu)化的SQL語(yǔ)句(或存儲(chǔ)過(guò)程)才能達(dá)到系統(tǒng)性能設(shè)計(jì)指標(biāo)。

ibatis 的著力點(diǎn):

在于POJO 與SQL之間的映射關(guān)系。也就是說(shuō),ibatis

并不會(huì)為程序員在運(yùn)行期自動(dòng)生成SQL 執(zhí)行。具體的SQL 需要程序員編寫,然后通過(guò)映射配置文件,將SQL所需的參數(shù),以及返回的結(jié)果字段映射到指定POJO。

Ibatis與Hibernate的區(qū)別:

Hibernate提供了全面的數(shù)據(jù)庫(kù)封裝機(jī)制的“全自動(dòng)化”ORM 實(shí)現(xiàn)而言,“全自動(dòng)”ORM 實(shí)現(xiàn)了POJO 和數(shù)據(jù)庫(kù)表之間的映射,以及SQL 的自動(dòng)生成和執(zhí)行,而ibatis 的著力點(diǎn),則在于POJO 與SQL之間的映射關(guān)系。也就是說(shuō),ibatis并不會(huì)為程序員在運(yùn)行期自動(dòng)生成SQL 執(zhí)行。具體的SQL 需要程序員編寫,然后通過(guò)映射配置文件,將SQL所需的參數(shù),以及返回的結(jié)果字段映射到指定POJO。

ibatis配置文件:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig

PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"

"

<sqlMapConfig>

<settings ⑴

cacheModelsEnabled="true"

enhancementEnabled="true"

lazyLoadingEnabled="true"

errorTracingEnabled="true"

maxRequests="32"

maxSessions="10"

maxTransactions="5"

useStatementNamespaces="false"

/>

<transactionManager type="JDBC"> ⑵

<dataSource type="SIMPLE"> ⑶

<property name="JDBC.Driver"

value="com.p6spy.engine.spy.P6SpyDriver"/>

<property name="JDBC.ConnectionURL"

value="jdbc:mysql://localhost/sample"/>

<property name="JDBC.Username" value="user"/>

<property name="JDBC.Password" value="mypass"/>

<property name="Pool.MaximumActiveConnections"

value="10"/>

<property name="Pool.MaximumIdleConnections" value="5"/>

<property name="Pool.MaximumCheckoutTime"

value="120000"/>

<property name="Pool.TimeToWait" value="500"/>

<property name="Pool.PingQuery" value="select 1 from

ACCOUNT"/>

<property name="Pool.PingEnabled" value="false"/>

<property name="Pool.PingConnectionsOlderThan"

value="1"/>

<property name="Pool.PingConnectionsNotUsedFor"

value="1"/>

</dataSource>

</transactionManager>

<sqlMap resource="com/ibatis/sample/User.xml"/> ⑷

<sqlMap resource="com/ibatis/sample/Address.xml"/>

</sqlMapConfig>

⑴Settings 節(jié)點(diǎn) 參數(shù)

描述

cacheModelsEnabled

是否啟用SqlMapClient上的緩存機(jī)制。建議設(shè)為"true"

enhancementEnabled

是否針對(duì)POJO啟用字節(jié)碼增強(qiáng)機(jī)制以提升getter/setter的調(diào)用效能,避免使用JavaReflect所帶來(lái)的性能開(kāi)銷。同時(shí),這也為L(zhǎng)azy Loading帶來(lái)了極大的性能提升。建議設(shè)為"true"

errorTracingEnabled

是否啟用錯(cuò)誤日志,在開(kāi)發(fā)期間建議設(shè)為"true"以方便調(diào)試

lazyLoadingEnabled

是否啟用延遲加載機(jī)制,建議設(shè)為"true"

maxRequests

最大并發(fā)請(qǐng)求數(shù)(Statement并發(fā)數(shù))

maxTransactions

最大并發(fā)事務(wù)數(shù)

maxSessions

最大Session 數(shù)。即當(dāng)前最大允許的并發(fā)SqlMapClient數(shù)。maxSessions設(shè)定必須介于maxTransactions和maxRequests之間,即 maxTransactions<maxSessions=<maxRequests

useStatementNamespaces

是否使用Statement命名空間。這里的命名空間指的是映射文件中,sqlMap節(jié)點(diǎn)的namespace屬性,如在上例中針對(duì)t_user

表的映射文件sqlMap節(jié)點(diǎn):

<sqlMap namespace="User">

這里,指定了此sqlMap節(jié)點(diǎn)下定義的操作均從屬于"User"命名空間。

在useStatementNamespaces="true"的情況下,Statement調(diào)用需追加命名空間,如:sqlMap.update("User.updateUser",user);否則直接通過(guò)Statement名稱調(diào)用即可,如:sqlMap.update("updateUser",user);

但請(qǐng)注意此時(shí)需要保證所有映射文件中,Statement定義無(wú)重名。

⑵ transactionManager節(jié)點(diǎn)

transactionManager 節(jié)點(diǎn)定義了ibatis 的事務(wù)管理器,目前提供了以下幾種選擇:

Ø JDBC

通過(guò)傳統(tǒng)JDBC Connection.commit/rollback實(shí)現(xiàn)事務(wù)支持。

Ø JTA

使用容器提供的JTA服務(wù)實(shí)現(xiàn)全局事務(wù)管理。

Ø EXTERNAL

外部事務(wù)管理,如在EJB中使用ibatis,通過(guò)EJB的部署配置即可實(shí)現(xiàn)自動(dòng)的事務(wù)管理機(jī)制。此時(shí)ibatis 將把所有事務(wù)委托給外部容器進(jìn)行管理。此外,通過(guò)Spring 等輕量級(jí)容器實(shí)現(xiàn)事務(wù)的配置化管理也是一個(gè)不錯(cuò)的選擇。關(guān)于結(jié)合容器實(shí)現(xiàn)事務(wù)管理,參見(jiàn)“高級(jí)特性”中的描述。

⑶ dataSource節(jié)點(diǎn)

dataSource從屬于transactionManager節(jié)點(diǎn),用于設(shè)定ibatis運(yùn)行期使用的DataSource屬性。

type屬性: dataSource節(jié)點(diǎn)的type屬性指定了dataSource的實(shí)現(xiàn)類型??蛇x項(xiàng)目:

Ø SIMPLE:

SIMPLE是ibatis內(nèi)置的dataSource實(shí)現(xiàn),其中實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)連接池機(jī)制,對(duì)應(yīng)ibatis 實(shí)現(xiàn)類為com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory。

Ø DBCP:

基于Apache DBCP 連接池組件實(shí)現(xiàn)的DataSource 封裝,當(dāng)無(wú)容器提供DataSource 服務(wù)時(shí),建議使用該選項(xiàng),對(duì)應(yīng)ibatis 實(shí)現(xiàn)類為com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory。

Ø JNDI:

使用J2EE 容器提供的DataSource 實(shí)現(xiàn),DataSource 將通過(guò)指定的JNDI Name 從容器中獲取。對(duì)應(yīng)ibatis 實(shí)現(xiàn)類為com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory。

dataSource的子節(jié)點(diǎn)說(shuō)明(SIMPLE&DBCP):

參數(shù)

描述

JDBC.Driver

JDBC 驅(qū)動(dòng)。如:com.microsoft.jdbc.sqlserver.SQLServerDriver

JDBC.ConnectionURL

數(shù)據(jù)庫(kù)URL。如:

jdbc:microsoft:sqlserver://localhost:1433;databaseName=ibatis如果用的是SQLServer JDBC Driver,需要在url后追加SelectMethod=Cursor以獲得JDBC事務(wù)的多Statement支持。

JDBC.Username

數(shù)據(jù)庫(kù)用戶名

JDBC.Password

數(shù)據(jù)庫(kù)用戶密碼

Pool.MaximumActiveConn

ections

數(shù)據(jù)庫(kù)連接池可維持的最大容量。

Pool.MaximumIdleConnec

tions

數(shù)據(jù)庫(kù)連接池中允許的掛起(idle)連接數(shù)。

以上子節(jié)點(diǎn)適用于SIMPLE 和DBCP 模式,分別針對(duì)SIMPLE 和DBCP 模式的DataSource私有配置節(jié)點(diǎn)如下:

SIMPLE:

Pool.MaximumCheckoutTime

數(shù)據(jù)庫(kù)聯(lián)接池中,連接被某個(gè)任務(wù)所允許占用的最大時(shí)間,如果超過(guò)這個(gè)時(shí)間限定,連接將被強(qiáng)制收回。(毫秒)

Pool.TimeToWait

當(dāng)線程試圖從連接池中獲取連接時(shí),連接池中無(wú)可用連接可供使用,此時(shí)線程將進(jìn)入等待狀態(tài),直到池中出現(xiàn)空閑連接。此參數(shù)設(shè)定了線程所允許等待的最長(zhǎng)時(shí)間。(毫秒)

Pool.PingQuery

數(shù)據(jù)庫(kù)連接狀態(tài)檢測(cè)語(yǔ)句。某些數(shù)據(jù)庫(kù)在連接在某段時(shí)間持續(xù)處于空閑狀態(tài)時(shí)會(huì)將其斷開(kāi)。而連接池管理器將通過(guò)此語(yǔ)句檢測(cè)池中連接是否可用。檢測(cè)語(yǔ)句應(yīng)該是一個(gè)最簡(jiǎn)化的無(wú)邏輯SQL。如“select 1 from t_user”,如果執(zhí)行此語(yǔ)句成功,連接池管理器將認(rèn)為此連接處于可用狀態(tài)

Pool.PingEnabled

是否允許檢測(cè)連接狀態(tài)。

Pool.PingConnectionsOlderThan

對(duì)持續(xù)連接時(shí)間超過(guò)設(shè)定值(毫秒)的連接進(jìn)行檢測(cè)。

Pool.PingConnectionsNotUsedFor

對(duì)空閑超過(guò)設(shè)定值(毫秒)的連接進(jìn)行檢測(cè)。

DBCP:

Pool.MaximumWait

當(dāng)線程試圖從連接池中獲取連接時(shí),連接池中無(wú)可用連接可供使用,此時(shí)線程將進(jìn)入等待狀態(tài),直到池中出現(xiàn)空閑連接。此參數(shù)設(shè)定了線程所允許等待的最長(zhǎng)時(shí)間。(毫秒)

Pool.ValidationQuery

數(shù)據(jù)庫(kù)連接狀態(tài)檢測(cè)語(yǔ)句。某些數(shù)據(jù)庫(kù)在連接在某段時(shí)間持續(xù)處于空閑狀態(tài)時(shí)會(huì)將其斷開(kāi)。而連接池管理器將通過(guò)此語(yǔ)句檢測(cè)池中連接是否可用。檢測(cè)語(yǔ)句應(yīng)該是一個(gè)最簡(jiǎn)化的無(wú)邏輯SQL。如“select 1 from t_user”,如果執(zhí)行此語(yǔ)句

成功,連接池管理器將認(rèn)為此連接處于可用狀態(tài)。

Pool.LogAbandoned

當(dāng)數(shù)據(jù)庫(kù)連接被廢棄時(shí),是否打印日志。

Pool.RemoveAbandonedTimeout

數(shù)據(jù)庫(kù)連接被廢棄的最大超時(shí)時(shí)間

Pool.RemoveAbandoned

當(dāng)連接空閑時(shí)間超過(guò)RemoveAbandonedTimeout時(shí),是否將其廢棄。

JNDI:

由于大部分配置是在應(yīng)用服務(wù)器中進(jìn)行,因此ibatis中的配置相對(duì)簡(jiǎn)單,下面是分別使用JDBC和JTA事務(wù)管理的JDNI配置:

使用JDBC事務(wù)管理的JNDI DataSource配置

<transactionManager type="JDBC" >

<dataSource type="JNDI">

<property name="DataSource" value="java:comp/env/jdbc/myDataSource"/>

</dataSource>

</transactionManager>

<transactionManager type="JTA" >

<property name="UserTransaction" value="java:/ctx/con/UserTransaction"/>

<dataSource type="JNDI">

<property name="DataSource" value="java:comp/env/jdbc/myDataSource"/>

</dataSource>

</transactionManager>

⑷ sqlMap節(jié)點(diǎn)

sqlMap 節(jié)點(diǎn)指定了映射文件的位置,配置中可出現(xiàn)多個(gè)sqlMap 節(jié)點(diǎn),以指定項(xiàng)目?jī)?nèi)所包含的所有映射文件。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"

"

<sqlMap namespace="映射文件名稱:User">

<typeAlias alias="user" type="com.ibatis.sample.User"/> 給對(duì)應(yīng)的類取別名

<cacheModel id="userCache" type="LRU">

<flushInterval hours="24"/> 設(shè)定緩存有效期

<flushOnExecute statement=" updateUser"/>

指定執(zhí)行特定Statement時(shí),將緩存清空。如updateUser操作將更新數(shù)據(jù)庫(kù)中的用戶信息,這將導(dǎo)致緩存中的數(shù)據(jù)對(duì)象與數(shù)據(jù)庫(kù)中的實(shí)際數(shù)據(jù)發(fā)生偏差,因此必須將緩存清空以避免臟數(shù)據(jù)的出現(xiàn)。

<property name="size" value="1000" /> CacheModel中最大容納的數(shù)據(jù)對(duì)象數(shù)量

</cacheModel>

申明了一個(gè)名為"userCache"的cacheModel,之后可以在Statement申明中對(duì)其進(jìn)行引用:例如:

<select id="getUser" parameterClass="java.lang.String" resultClass="user"

cacheModel="userCache">

<select id="" parameterClass="java.lang.String" resultClass="user">

<![CDATA[    可以避免SQL 中與XML 規(guī)范相沖突的字符對(duì)XML映射文件的合法性造成影響。

SQL語(yǔ)句

]]>

</select>

< update id=" " parameterClass="java.lang.String" >

<![CDATA[

SQL語(yǔ)句

]]>

</ update >

< insert id=" " parameterClass="java.lang.String" >

<![CDATA[

SQL語(yǔ)句

]]>

</ insert >

< delete id="" parameterClass="java.lang.String" >

<![CDATA[

SQL語(yǔ)句

]]>

</ delete >

</sqlMap>

需要一個(gè)JAVABEAN:有g(shù)etter和setter方法

如何讀取配置文件:

       public class SQLMapper {

       public static SqlMapClient sqlMapper;

       static{

              String resource = "org/lzp/xml/SqlMapConfig.xml";指明了配置文件的相對(duì)路徑

              try {

                     Reader reader = Resources.getResourceAsReader(resource);

           //ibatis2.0

           /* XmlSqlMapClientBuilder xmlBuilder =

new XmlSqlMapClientBuilder();

sqlMapper = xmlBuilder.buildSqlMap(reader);

*/

//ibatis1.0

                     sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);

              } catch (Exception e) {

                     e.printStackTrace();

              }

       }

}

SqlMapClient是ibatis運(yùn)作的核心,所有操作均通過(guò)SqlMapClient實(shí)例完成。例如:

sqlMapper.insert("名稱", 參數(shù));

sqlMapper提供了眾多數(shù)據(jù)操作方法,下面是一些常用方法的示例,具體說(shuō)明文檔請(qǐng)參見(jiàn)ibatis java doc,或者ibatis官方開(kāi)發(fā)手冊(cè)。

Statement配置:

Statement配置包含了數(shù)個(gè)與SQL Statement相關(guān)的節(jié)點(diǎn),分別為:

u statement: 最為通用,它可以替代其余的所有節(jié)點(diǎn)。

u insert

u delete

u update

u select

u procedure

參數(shù)描述:可以是類、基本數(shù)據(jù)類型和MAP進(jìn)行傳值

參數(shù)

描述

parameterClass

參數(shù)類。指定了參數(shù)的完整類名(包括包路徑)。

可通過(guò)別名避免每次重復(fù)書寫冗長(zhǎng)的類名。

resultClass

結(jié)果類。指定結(jié)果類型的完整類名(包括包路徑)

可通過(guò)別名避免每次重復(fù)書寫冗長(zhǎng)的類名。

parameterMap

參數(shù)映射,需結(jié)合parameterMap節(jié)點(diǎn)對(duì)映射關(guān)系加以定義。對(duì)于存儲(chǔ)過(guò)程之外的statement而言,建議使用parameterClass作為參數(shù)配置方式,一方面避免了參數(shù)映射配置工作,另一方面其性能表現(xiàn)也更加出色。

resultMap

結(jié)果映射,需結(jié)合resultMap節(jié)點(diǎn)對(duì)映射關(guān)系加以定義。

cacheModel

statement對(duì)應(yīng)的Cache模塊。

動(dòng)態(tài)映射:

<select id="getUsers" parameterClass="user" resultClass="user">

Select id,name,sex from t_user

<dynamic prepend="WHERE">

<isNotEmpty prepend="AND" property="name">

(name like #name#)

</isNotEmpty>

<isNotEmpty prepend="AND" property="address">

(address like #address#)

</isNotEmpty>

</dynamic>

</select>

Ø 一元判定: 是針對(duì)屬性值本身的判定,如屬性是否為NULL,是否為空值等。

一元判定節(jié)點(diǎn)有:

節(jié)點(diǎn)名

描述

<isPropertyAvailable>

參數(shù)類中是否提供了此屬性

<isNotPropertyAvailable>

與<isPropertyAvailable>相反

<isNull>

屬性值是否為NULL

<isNotNull>

與<isNull>相反

<isEmpty>

如果屬性為Collection或者String,其size是否<1,

如果非以上兩種類型,則通過(guò)

String.valueOf(屬性值)

獲得其String類型的值后,判斷其size是否<1

<isNotEmpty>

與<isEmpty>相反。

Ø 二元判定

二元判定有兩個(gè)判定參數(shù),一是屬性名,而是判定值,如

<isGreaterThan prepend="AND" property="age" compareValue="18">

(age=#age#)

</isGreaterThan>

其中,property="age"指定了屬性名”age”,compareValue=”18”指明了判定值為”18”。上面判定節(jié)點(diǎn)isGreaterThan 對(duì)應(yīng)的語(yǔ)義是:如果age 屬性大于

18(compareValue),則在SQL中加入(age=#age#)條件。

二元判定節(jié)點(diǎn)有:

節(jié)點(diǎn)名

屬性值與compareValues的關(guān)系

<isEqual>

相等。

<isNotEqual>

不等。

<isGreaterThan>

大于

<isGreaterEqual>

大于等于

<isLessThan>

小于

<isLessEqual>

小于等于