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

自動化”的ORM實現(xiàn)。

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

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

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

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

ibatis 的著力點:

在于POJO 與SQL之間的映射關系。也就是說,ibatis

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

Ibatis與Hibernate的區(qū)別:

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

描述

cacheModelsEnabled

是否啟用SqlMapClient上的緩存機制。建議設為"true"

enhancementEnabled

是否針對POJO啟用字節(jié)碼增強機制以提升getter/setter的調用效能,避免使用JavaReflect所帶來的性能開銷。同時,這也為Lazy Loading帶來了極大的性能提升。建議設為"true"

errorTracingEnabled

是否啟用錯誤日志,在開發(fā)期間建議設為"true"以方便調試

lazyLoadingEnabled

是否啟用延遲加載機制,建議設為"true"

maxRequests

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

maxTransactions

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

maxSessions

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

useStatementNamespaces

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

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

<sqlMap namespace="User">

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

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

但請注意此時需要保證所有映射文件中,Statement定義無重名。

⑵ transactionManager節(jié)點

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

Ø JDBC

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

Ø JTA

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

Ø EXTERNAL

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

⑶ dataSource節(jié)點

dataSource從屬于transactionManager節(jié)點,用于設定ibatis運行期使用的DataSource屬性。

type屬性: dataSource節(jié)點的type屬性指定了dataSource的實現(xiàn)類型。可選項目:

Ø SIMPLE:

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

Ø DBCP:

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

Ø JNDI:

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

dataSource的子節(jié)點說明(SIMPLE&DBCP):

參數(shù)

描述

JDBC.Driver

JDBC 驅動。如:com.microsoft.jdbc.sqlserver.SQLServerDriver

JDBC.ConnectionURL

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

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

JDBC.Username

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

JDBC.Password

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

Pool.MaximumActiveConn

ections

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

Pool.MaximumIdleConnec

tions

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

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

SIMPLE:

Pool.MaximumCheckoutTime

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

Pool.TimeToWait

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

Pool.PingQuery

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

Pool.PingEnabled

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

Pool.PingConnectionsOlderThan

對持續(xù)連接時間超過設定值(毫秒)的連接進行檢測。

Pool.PingConnectionsNotUsedFor

對空閑超過設定值(毫秒)的連接進行檢測。

DBCP:

Pool.MaximumWait

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

Pool.ValidationQuery

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

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

Pool.LogAbandoned

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

Pool.RemoveAbandonedTimeout

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

Pool.RemoveAbandoned

當連接空閑時間超過RemoveAbandonedTimeout時,是否將其廢棄。

JNDI:

由于大部分配置是在應用服務器中進行,因此ibatis中的配置相對簡單,下面是分別使用JDBC和JTA事務管理的JDNI配置:

使用JDBC事務管理的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é)點

sqlMap 節(jié)點指定了映射文件的位置,配置中可出現(xiàn)多個sqlMap 節(jié)點,以指定項目內(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"/> 給對應的類取別名

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

<flushInterval hours="24"/> 設定緩存有效期

<flushOnExecute statement=" updateUser"/>

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

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

</cacheModel>

申明了一個名為"userCache"的cacheModel,之后可以在Statement申明中對其進行引用:例如:

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

cacheModel="userCache">

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

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

SQL語句

]]>

</select>

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

<![CDATA[

SQL語句

]]>

</ update >

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

<![CDATA[

SQL語句

]]>

</ insert >

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

<![CDATA[

SQL語句

]]>

</ delete >

</sqlMap>

需要一個JAVABEAN:有getter和setter方法

如何讀取配置文件:

       public class SQLMapper {

       public static SqlMapClient sqlMapper;

       static{

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

              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運作的核心,所有操作均通過SqlMapClient實例完成。例如:

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

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

Statement配置:

Statement配置包含了數(shù)個與SQL Statement相關的節(jié)點,分別為:

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

u insert

u delete

u update

u select

u procedure

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

參數(shù)

描述

parameterClass

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

可通過別名避免每次重復書寫冗長的類名。

resultClass

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

可通過別名避免每次重復書寫冗長的類名。

parameterMap

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

resultMap

結果映射,需結合resultMap節(jié)點對映射關系加以定義。

cacheModel

statement對應的Cache模塊。

動態(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>

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

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

節(jié)點名

描述

<isPropertyAvailable>

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

<isNotPropertyAvailable>

與<isPropertyAvailable>相反

<isNull>

屬性值是否為NULL

<isNotNull>

與<isNull>相反

<isEmpty>

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

如果非以上兩種類型,則通過

String.valueOf(屬性值)

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

<isNotEmpty>

與<isEmpty>相反。

Ø 二元判定

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

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

(age=#age#)

</isGreaterThan>

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

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

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

節(jié)點名

屬性值與compareValues的關系

<isEqual>

相等。

<isNotEqual>

不等。

<isGreaterThan>

大于

<isGreaterEqual>

大于等于

<isLessThan>

小于

<isLessEqual>

小于等于