ibatis sqlMap 使用

SqlMap的配置是iBatis中應用的核心。這部分任務佔據了iBatis開發的70的工做量。java

一、命名空間:sql

<sqlMap namespace="Account">

在此空間外要引用此空間的元素,則須要加上命名空間名。數據庫

二、實體的別名:apache

<typeAlias alias="Account" type="com.lavasoft.ibatissut.simple.domain.entity.Account"/>

若是有用到的全名的地方,能夠用別名代替,受命名空間約束。緩存

三、插入操做
    對於自增主鍵的表,插入能夠不配置插入的主鍵列。不然是必須的。dom

四、獲取主鍵
     插入語句以前配置:主要是針對Sequence主鍵而言,插入前必須指定一個主鍵值給要插入的記錄。Oracle、DB2亦如此,方法是在插入語句標籤<insert....>以前配置上:工具

<insert id="insertAccount" parameterClass="Account">
        <selectKey resultClass="long" keyProperty="sctId">
            SELECT SEQ_TEST.NEXTVAL FROM DUAL
        </selectKey>  
        insert into .... ........
</insert>

 插入語句以後配置:主要是針對自增主鍵的表而言,這類表在插入時不須要主鍵,而是在插入過程自動獲取一個自增的主鍵。好比MySQLpost

   <insert id="insertAccount" parameterClass="Account">
        <selectKey resultClass="long" keyProperty="sctId">
            SELECT LAST_INSERT_ID()
       </selectKey>  
        insert into .... ........
    </insert>

   固然,是否須要配置<selectKey>根據狀況,只要能保證記錄有主鍵便可。一旦配置了<selectKey>,就能夠在執行插入操做時獲取到新增記錄的主鍵。性能

六、SQL入參parameterClass
   插入語句入參:parameterClass="類別名"  來設定。
  查詢語句入參:能夠設定類別名,也能夠設定爲map,也能夠設定爲iBatis支持的原生類型(好比string、int、long等),當只有一個原生類型入參時,使用#value#來引用,這個value是否是關鍵字,可變。好比:    學習

<select id="getById"  parameterClass="long" resultMap="result_base">
        select * from customer where id = #value#
</select>

 map是最強大的入參方式,任何入參方式均可以轉換爲這種入參方式,由於iBatis僅接受一個入參,當幾個參數分佈在不一樣對象中的時候,將這些對象的屬性(或者對象自己put)到map中,而後一次傳遞給sql語句是很是有效。能夠本身寫一個將對象或者對象集合轉換爲map的工具(我已經實現一個了)。
    另外,map的中的元素(好比pobj)是個複雜對象,則還能夠在SQL中以#pobj.protyename#的格式來引用其中內嵌的屬性。固然不推薦這麼幹。

七、返回值參數類型
      返回值參數也一樣有兩種類型,一種是對象類型resultClass="Account",一種是resultMap="AccountResult"。這兩種類型的選擇經常會使人疑惑不解,一言明其理:
當結果集列名和類屬性名徹底對應的時候,則應該使用resultClass來指定查詢結果類型。固然有些列明不對應,能夠在sql中使用as重命名達到一致的效果。

當查詢結果列名和類屬性名對應不上的時候,應該選擇 resultMap指定查詢結果集類型。不然,則查詢出來填充的對象屬性爲空(數字的爲0,對象的爲null)。

可是實際上 resultMap是對一個Java Bean的映射,須要先定義xml的映射後,才能夠引用,例如: 

<resultMap id="AccountResult" class="Account">
        <result property="id" column="ACC_ID"/>
        <result property="firstName" column="ACC_FIRST_NAME"/>
        <result property="lastName" column="ACC_LAST_NAME"/>
        <result property="emailAddress" column="ACC_EMAIL"/>
    </resultMap>


    resultMap映射的結果的目的就是要將查詢的結果集綁定到映射對象的屬性上。

   無論使用哪一種返回值參數類型,其最終目的就是要把每條記錄映射到一個類的對象或者對象集合上,若是有某個類屬性映射不上,則在獲得的這個對象或對象集合中這個屬性爲空。映射的屬性能夠是表與實體中的一部分。不要同時使用兩種返回值參數類型,這樣只會使人迷惑。

八、查詢結果集分組
    查詢結果集排序有兩種方式:一是在結果集映射上定義<resultMap id="result" class="bar" groupBy="id">,另外一種就是在SQL語句中分組。建議在SQL語句中分組,以得到更大的可控制性。

九、 SQL中參數的引用
     SQL中引用parameterClass的參數有三種方式:
     iBatis內置支持的類型,好比int、string,使用#value#來引用,這個value是否是關鍵字,可變。
     map類型的參數,使用#keyName#來引用,keyName爲鍵名。
     複雜對象的參數,使用#propertyName#來引用,propertyName類屬性的名字。

十、模糊查詢中參數的引用
    模糊查詢是針對字符串而言的,若是遇到兩個單引號要包含一個參數,則不能再用#來引用變量了,而應該改成$,好比:'%$varName$%',固然,也可使用 '%' || #varname# || '%' 來繞過此問題。

十一、SQL片斷
       能夠經過

<sql id="sql_xxx">...</sql>

定義SQL片斷,而後

<include refid="sql_xxx"/>

來在各類語句中引用,達到複用目的。

十二、動態SQL
      能夠經過使用動態SQL來組織靈活性更大的更通用的SQL,這樣極大減小了編碼量,是iBatis應用的第二大亮點。
     好比:一個動態的where條件
               

<dynamic prepend="where">
                        <isNotEmpty prepend="and" property="$$$$$">
                                $name like '%'|| #$name# ||'%'
                        </isNotEmpty>
                        <isGreaterThan prepend="and" property="$$$$$" compareValue="$$$number">
                                $code like '%'|| #$code# ||'%'
                        </isGreaterThan>
                </dynamic>


     固然,prepend表示連接關鍵字,能夠爲任何字符串,當爲sql關鍵字時,iBatis自動判斷是否應該添加該關鍵字。該語法也很簡單,關鍵是要會用心思考組織動態SQL。
    這裏面有一點要注意:區別<isNotEmpty>和<isNotNull>區別,當爲空空串時<isNotEmpty>返回true,當爲空串時<isNotNull>返回真。哈哈,本身體會吧,說了反而囉嗦。

1三、結果集映射繼承
結果集映射的繼承的目的是爲了映射定義的複用,好比下面定義了兩個映射,AccountResult繼承了base:
   

<resultMap id="base" class="Account">
        <result property="id" column="ACC_ID"/>
        <result property="firstName" column="ACC_FIRST_NAME"/>
        <result property="lastName" column="ACC_LAST_NAME"/>
    </resultMap>
    <resultMap id="AccountResult" class="Account" extends="Account.base">
        <result property="emailAddress" column="ACC_EMAIL"/>
    </resultMap>


這樣,就很容易擴展了一個映射策略。
       
1四、查詢注入
查詢注入是在一個查詢中嵌入另一個查詢,這樣作的目的是爲了實現實體對象之間的關聯關聯關係(一對1、一對多、多對多)分單項雙向。有關這些內容,是比較複雜的,筆者對此作了深刻研究,並分別寫了三篇來說述。

查詢注入的實現就是在實體屬性爲另一個實體或者實體集合的時候,引入一個相關的查詢來實現,例如,客戶和訂單的映射關係:

public class Customer {
    private Long id;
    private String name;
    private String address;
    private String postcode;
    private String sex;
    private List<Orders> orderlist = new ArrayList<Orders>();

   

<resultMap id="result" class="customer">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="address" column="address"/>
        <result property="postcode" column="postcode"/>
        <result property="sex" column="sex"/>
        <result property="orderlist" column="id" select="orders.findByCustomerId "/>
    </resultMap>

在這個映射中,爲了查詢客戶的時候,能查詢到相關的訂單,能夠在映射orderlist 屬性的時候,將其指向另一個查詢orders.findByCustomerId ,這個查詢是以Customer的id 爲參數來查詢的。

select="orders.findByCustomerId " 這個查詢定義以下:
   

<select id="findByCustomerId" resultMap="result_base" parameterClass="long">
        select * from orders where customerId = #value#
    </select>

原理就是這麼簡單,而後根據實際狀況,能夠自由實現實體間的關聯關係。

1五、iBatis的分頁查詢
iBatis 的分頁有兩種方式,一點都不神祕,不要被網上的流言所迷惑。

  • 第一種方式:結果集篩選分頁。先執行部分頁的SQL查詢語句,而後獲得一個 ResultSet,而後根據分頁範圍選擇有效的記錄填充到對象中,最終以集合的形式返回。對於10w條一下的記錄的表,不存在性能問題,若是存在,你能夠選擇第二中方式。
  • 第二種方式:SQL分頁,經過組裝分頁類型的SQL來實現分頁。這個關鍵在於分頁參數的傳遞和分頁SQL的構建。分頁SQL構件每種數據庫都不同,不說了。分頁參數的傳遞卻能夠通用。我主張用map分裝入參,連同分頁參數一塊傳遞進來,就搞定了。若是原來沒有考慮到分頁,而用的是對象作參數,則能夠經過apache 的 beanutils組件來實現一個object到map之間的轉換工具,問題迎刃而解。

固然,這還不是分頁查詢應用的最高境界。思考,分頁須要計算一個總記錄數,記錄數執行的sql返回值是count(?),條件是除了分頁之外的條件,所以應該將查詢SQL靜態分開,以MySQL爲例,能夠將查詢分爲查什麼,和什麼條件兩部分,在條件部分對分頁參數進行動態判斷,若是分頁參數就不分頁,若是有則分頁。這樣最後只須要兩個組裝的sql就能夠計算總數和分頁查詢了。大大簡化了問題的難度。 Oracle的解決思路也同樣,不同的地方就是拼裝分頁SQL改變了。

1六、執行存儲過程的配置
SQL Map 經過<procedure>元素支持存儲過程。下面的例子說明如何使用具備輸出參數
的存儲過程。
  

  <parameterMap id="swapParameters" class="map">
        <parameter property="email1" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/>
        <parameter property="email2" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/>
    </parameterMap>
    <procedure id="swapEmailAddresses" parameterMap="swapParameters">
        {call swap_email_address (?, ?)}
    </procedure>


調用上面的存儲過程將同時互換兩個字段(數據庫表)和參數對象(Map)中的兩個 email地址。若是參數的 mode 屬性設爲 INOUT 或 OUT,則參數對象的值被修改。不然保持不變。
注意!要確保始終只使用 JDBC 標準的存儲過程語法。參考 JDBC 的 CallableStatement
文檔以得到更詳細的信息。

1七、就是iBatis中各類id的命名了

這個看起來小菜一碟,可是搞砸了會很痛苦。建議若是有DAO層的話,DAO接口的名字和SQL語句 id的名字保持一致。同時,在DAO中將save和update封裝爲一個方法(從Hibernate中學來的),這是很是好的。也能夠直接在SQL層將插入和更新柔和在一塊,太複雜,有點影響效率,這見機行事了。

   另外Spring提供了各類數據操做模板,經過模板,擦作數據也就是「一句話」的問題,寫個DAO還有必要麼,尤爲對iBatis來講,根本沒有必要。這樣,就須要在領域活動層的設計上下功夫了。

18 、iBatis的查詢也能夠配置緩存策略

緩存的配置很複雜,分不少中狀況,能夠參看附件中的iBATIS-SqlMaps-2_cn.pdf 的39頁內容,有詳細介紹。

1九、偷懶的最高境界,讓程序去幹哪裏80%的體力活。本身僅僅把把關。任何重複的活動都有規律可循的,一旦發現了其中的規律,你就能夠想辦法把本身從中解脫出來。
    iBatis也不例外,每一個表都有增刪改查、分頁等操做。對應在每一個DAO方法上亦如此。能夠經過數據庫生成sqlmap、entity、dao,而後將這些東西改吧改吧就完成大部分的工做量。本人已經實現過了,固然開發這個工具的前提是你對iBatis有深刻研究和理解。

-------------------------------------------------
下面是iBatis開發指南中內容:

附錄:容易出錯的地方
本附錄是譯者添加的,列出了初學者容易出錯的地方,做爲完成快速入門課程後的學習
筆記,可讓初學者少走些彎路。僅供參考。
1)  在 parameterMap 和 resultMap 中,字段數據類型是 java.sql.Types 類定義的常量名
稱。經常使用的數據類型包括 BLOB,CHAR,CLOB,DATE,LONGVARBINARY,
INTEGER,NULL,NUMERIC,TIME,TIMESTAMP 和 VARCHAR 等。
2)  對於數據表中 NULLABLE 的字段,必須在 parameterMap 和 resultMap 中指定字段
的數據類型。
3)  對於數據類型是 DATE,CLOB 或 BLOB 的字段,最好在 parameterMap 和 resultMap中指定數據類型。
4)  對於二進制類型的數據,能夠將 LONGVARBINARY 映射成 byte[]。
5)  對於文本類型較大的數據,能夠將 CLOB 映射成 String。
6) Java Bean 必須擁有缺省的構造器(即無參數的構造器)。
7) Java Bean 最好實現 Serializable 接口,以備應用的進一步擴展。

本人認爲:儘可能避免在每一個入參後面附加參數的類型。以保持配置簡潔,而且本人在長期開發中,沒有發現必需要那麼作。

相關文章
相關標籤/搜索