iBatis SqlMap的配置总结
生活随笔
收集整理的這篇文章主要介紹了
iBatis SqlMap的配置总结
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
核心提示:SqlMap的配置是iBatis中應(yīng)用的核心。這部分任務(wù)占據(jù)了iBatis開(kāi)發(fā)的70的工作量。 1、命名空間: sqlMap namespace=Account,在此空間外要引用此空間的元素,則需要加上命名空間名。 2、實(shí)體的別名: typeAlias alias=Account type=com.lavasoft.ibatissut.sim?
SqlMap的配置是iBatis中應(yīng)用的核心。這部分任務(wù)占據(jù)了iBatis開(kāi)發(fā)的70的工作量。?
1、命名空間:?
? <sqlMap namespace="Account">,在此空間外要引用此空間的元素,則需要加上命名空間名。?
2、實(shí)體的別名:?
? <typeAlias alias="Account" type="com.lavasoft.ibatissut.simple.domain.entity.Account"/>?
? 如果有用到的全名的地方,可以用別名代替,受命名空間約束。?
3、插入操作?
??? 對(duì)于自增主鍵的表,插入可以不配置插入的主鍵列。否則是必須的。?
4、獲取主鍵?
???? 插入語(yǔ)句之前配置:主要是針對(duì)Sequence主鍵而言,插入前必須指定一個(gè)主鍵值給要插入的記錄。Oracle、DB2亦如此,方法是在插入語(yǔ)句標(biāo)簽<insert....>之前配置上:?
??? <insert id="insertAccount" parameterClass="Account">?
??????? <selectKey resultClass="long" keyProperty="sctId">?
??????????? SELECT SEQ_TEST.NEXTVAL FROM DUAL?
??????? </selectKey>??
??????? insert into .... ........?
??? </insert>?
??
??? 插入語(yǔ)句之后配置:主要是針對(duì)自增主鍵的表而言,這類表在插入時(shí)不需要主鍵,而是在插入過(guò)程自動(dòng)獲取一個(gè)自增的主鍵。比如MySQL?
??? <insert id="insertAccount" parameterClass="Account">?
??????? <selectKey resultClass="long" keyProperty="sctId">?
??????????? SELECT LAST_INSERT_ID()?
?????? </selectKey>??
??????? insert into .... ........?
??? </insert>?
?? 當(dāng)然,是否需要配置<selectKey>根據(jù)情況,只要能保證記錄有主鍵即可。一旦配置了<selectKey>,就可以在執(zhí)行插入操作時(shí)獲取到新增記錄的主鍵。?
6、SQL入?yún)arameterClass?
? 插入語(yǔ)句入?yún)?#xff1a;parameterClass="類別名"? 來(lái)設(shè)定。?
? 查詢語(yǔ)句入?yún)?#xff1a;可以設(shè)定類別名,也可以設(shè)定為map,也可以設(shè)定為iBatis支持的原生類型(比如string、int、long等),當(dāng)只有一個(gè)原生類型入?yún)r(shí),使用#value#來(lái)引用,這個(gè)value是不是關(guān)鍵字,可變。比如:?
??? <select id="getById"? parameterClass="long" resultMap="result_base">?
??????? select * from customer where id = #value#?
??? </select>?
??? map是最強(qiáng)大的入?yún)⒎绞?#xff0c;任何入?yún)⒎绞蕉伎梢赞D(zhuǎn)換為這種入?yún)⒎绞?#xff0c;因?yàn)閕Batis僅接受一個(gè)入?yún)?#xff0c;當(dāng)幾個(gè)參數(shù)分布在不同對(duì)象中的時(shí)候,將這些對(duì)象的屬性(或者對(duì)象本身put)到map中,然后一次傳遞給sql語(yǔ)句是非常有效。可以自己寫(xiě)一個(gè)將對(duì)象或者對(duì)象集合轉(zhuǎn)換為map的工具(我已經(jīng)實(shí)現(xiàn)一個(gè)了)。?
??? 另外,map的中的元素(比如pobj)是個(gè)復(fù)雜對(duì)象,則還可以在SQL中以#pobj.protyename#的格式來(lái)引用其中內(nèi)嵌的屬性。當(dāng)然不推薦這么干。?
7、返回值參數(shù)類型?
????? 返回值參數(shù)也同樣有兩種類型,一種是對(duì)象類型resultClass="Account",一種是resultMap="AccountResult"。這兩種類型的選擇常常會(huì)令人迷惑不解,一言明其理:?
當(dāng)結(jié)果集列名和類屬性名完全對(duì)應(yīng)的時(shí)候,則應(yīng)該使用resultClass來(lái)指定查詢結(jié)果類型。當(dāng)然有些列明不對(duì)應(yīng),可以在sql中使用as重命名達(dá)到一致的效果。?
當(dāng)查詢結(jié)果列名和類屬性名對(duì)應(yīng)不上的時(shí)候,應(yīng)該選擇 resultMap指定查詢結(jié)果集類型。否則,則查詢出來(lái)填充的對(duì)象屬性為空(數(shù)字的為0,對(duì)象的為null)。?
但是實(shí)際上 resultMap是對(duì)一個(gè)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映射的結(jié)果的目的就是要將查詢的結(jié)果集綁定到映射對(duì)象的屬性上。?
?? 不管使用哪種返回值參數(shù)類型,其最終目的就是要把每條記錄映射到一個(gè)類的對(duì)象或者對(duì)象集合上,如果有某個(gè)類屬性映射不上,則在得到的這個(gè)對(duì)象或?qū)ο蠹现羞@個(gè)屬性為空。映射的屬性可以是表與實(shí)體中的一部分。不要同時(shí)使用兩種返回值參數(shù)類型,這樣只會(huì)令人迷惑。?
8、查詢結(jié)果集分組?
??? 查詢結(jié)果集排序有兩種方式:一是在結(jié)果集映射上定義<resultMap id="result" class="bar" groupBy="id">,另一種就是在SQL語(yǔ)句中分組。建議在SQL語(yǔ)句中分組,以獲得更大的可控制性。?
9、 SQL中參數(shù)的引用?
???? SQL中引用parameterClass的參數(shù)有三種方式:?
???? iBatis內(nèi)置支持的類型,比如int、string,使用#value#來(lái)引用,這個(gè)value是不是關(guān)鍵字,可變。?
???? map類型的參數(shù),使用#keyName#來(lái)引用,keyName為鍵名。?
???? 復(fù)雜對(duì)象的參數(shù),使用#propertyName#來(lái)引用,propertyName類屬性的名字。?
10、模糊查詢中參數(shù)的引用?
??? 模糊查詢是針對(duì)字符串而言的,如果遇到兩個(gè)單引號(hào)要包含一個(gè)參數(shù),則不能再用#來(lái)引用變量了,而應(yīng)該改為$,比如:'%$varName$%',當(dāng)然,也可以使用 '%' || #varname# || '%' 來(lái)繞過(guò)此問(wèn)題。?
11、SQL片段?
?????? 可以通過(guò)<sql id="sql_xxx">...</sql>定義SQL片段,然后<include refid="sql_xxx"/>來(lái)在各種語(yǔ)句中引用,達(dá)到復(fù)用目的。?
12、動(dòng)態(tài)SQL?
????? 可以通過(guò)使用動(dòng)態(tài)SQL來(lái)組織靈活性更大的更通用的SQL,這樣極大減少了編碼量,是iBatis應(yīng)用的第二大亮點(diǎn)。?
???? 比如:一個(gè)動(dòng)態(tài)的where條件?
??????????????? <dynamic prepend="where">?
??????????????????????? <isNotEmpty prepend="and" property="$$$$$">?
??????????????????????????????? $name like '%'|| #$name# ||'%'?
??????????????????????? </isNotEmpty>?
??????????????????????? <isGreaterThan prepend="and" property="$$$$$" compareValue="$$$number">?
??????????????????????????????? $code like '%'|| #$code# ||'%'?
??????????????????????? </isGreaterThan>?
??????????????? </dynamic>?
???? 當(dāng)然,prepend表示鏈接關(guān)鍵字,可以為任何字符串,當(dāng)為sql關(guān)鍵字時(shí),iBatis自動(dòng)判斷是否應(yīng)該添加該關(guān)鍵字。該語(yǔ)法也很簡(jiǎn)單,關(guān)鍵是要會(huì)用心思考組織動(dòng)態(tài)SQL。?
??? 這里面有一點(diǎn)要注意:區(qū)別<isNotEmpty>和<isNotNull>區(qū)別,當(dāng)為空空串時(shí)<isNotEmpty>返回true,當(dāng)為空串時(shí)<isNotNull>返回真。哈哈,自己體會(huì)吧,說(shuō)了反而啰嗦。?
13、結(jié)果集映射繼承?
結(jié)果集映射的繼承的目的是為了映射定義的復(fù)用,比如下面定義了兩個(gè)映射,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>?
這樣,就很容易擴(kuò)展了一個(gè)映射策略。?
???????
14、查詢注入?
查詢注入是在一個(gè)查詢中嵌入另外一個(gè)查詢,這樣做的目的是為了實(shí)現(xiàn)實(shí)體對(duì)象之間的關(guān)聯(lián)關(guān)聯(lián)關(guān)系(一對(duì)一、一對(duì)多、多對(duì)多)分單項(xiàng)雙向。有關(guān)這些內(nèi)容,是比較復(fù)雜的,筆者對(duì)此做了深入研究,并分別寫(xiě)了三篇來(lái)講述。?
查詢注入的實(shí)現(xiàn)就是在實(shí)體屬性為另外一個(gè)實(shí)體或者實(shí)體集合的時(shí)候,引入一個(gè)相關(guān)的查詢來(lái)實(shí)現(xiàn),例如,客戶和訂單的映射關(guān)系:?
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>?
在這個(gè)映射中,為了查詢客戶的時(shí)候,能查詢到相關(guān)的訂單,可以在映射orderlist 屬性的時(shí)候,將其指向另外一個(gè)查詢orders.findByCustomerId ,這個(gè)查詢是以Customer的id 為參數(shù)來(lái)查詢的。?
select="orders.findByCustomerId " 這個(gè)查詢定義如下:?
??? <select id="findByCustomerId" resultMap="result_base" parameterClass="long">?
??????? select * from orders where customerId = #value#?
??? </select>?
原理就是這么簡(jiǎn)單,然后根據(jù)實(shí)際情況,可以自由實(shí)現(xiàn)實(shí)體間的關(guān)聯(lián)關(guān)系。?
14、iBatis的分頁(yè)查詢?
iBatis 的分頁(yè)有兩種方式,一點(diǎn)都不神秘,不要被網(wǎng)上的流言所迷惑。?
第一種方式:結(jié)果集篩選分頁(yè)。先執(zhí)行部分頁(yè)的SQL查詢語(yǔ)句,然后得到一個(gè) ResultSet,然后根據(jù)分頁(yè)范圍選擇有效的記錄填充到對(duì)象中,最終以集合的形式返回。對(duì)于10w條一下的記錄的表,不存在性能問(wèn)題,如果存在,你可以選擇第二中方式。?
第二種方式:SQL分頁(yè),通過(guò)組裝分頁(yè)類型的SQL來(lái)實(shí)現(xiàn)分頁(yè)。這個(gè)關(guān)鍵在于分頁(yè)參數(shù)的傳遞和分頁(yè)SQL的構(gòu)建。分頁(yè)SQL構(gòu)件每種數(shù)據(jù)庫(kù)都不一樣,不說(shuō)了。分頁(yè)參數(shù)的傳遞卻可以通用。我主張用map分裝入?yún)?#xff0c;連同分頁(yè)參數(shù)一塊傳遞進(jìn)來(lái),就搞定了。如果原來(lái)沒(méi)有考慮到分頁(yè),而用的是對(duì)象做參數(shù),則可以通過(guò)apache 的 beanutils組件來(lái)實(shí)現(xiàn)一個(gè)object到map之間的轉(zhuǎn)換工具,問(wèn)題迎刃而解。?
當(dāng)然,這還不是分頁(yè)查詢應(yīng)用的最高境界。思考,分頁(yè)需要計(jì)算一個(gè)總記錄數(shù),記錄數(shù)執(zhí)行的sql返回值是count(?),條件是除了分頁(yè)以外的條件,因此應(yīng)該將查詢SQL靜態(tài)分開(kāi),以MySQL為例,可以將查詢分為查什么,和什么條件兩部分,在條件部分對(duì)分頁(yè)參數(shù)進(jìn)行動(dòng)態(tài)判斷,如果分頁(yè)參數(shù)就不分頁(yè),如果有則分頁(yè)。這樣最后只需要兩個(gè)組裝的sql就可以計(jì)算總數(shù)和分頁(yè)查詢了。大大簡(jiǎn)化了問(wèn)題的難度。 Oracle的解決思路也一樣,不一樣的地方就是拼裝分頁(yè)SQL改變了。?
15、執(zhí)行存儲(chǔ)過(guò)程的配置?
SQL Map 通過(guò)<procedure>元素支持存儲(chǔ)過(guò)程。下面的例子說(shuō)明如何使用具有輸出參數(shù)?
的存儲(chǔ)過(guò)程。?
??? <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>?
調(diào)用上面的存儲(chǔ)過(guò)程將同時(shí)互換兩個(gè)字段(數(shù)據(jù)庫(kù)表)和參數(shù)對(duì)象(Map)中的兩個(gè) email地址。如果參數(shù)的 mode 屬性設(shè)為 INOUT 或 OUT,則參數(shù)對(duì)象的值被修改。否則保持不變。?
注意!要確保始終只使用 JDBC 標(biāo)準(zhǔn)的存儲(chǔ)過(guò)程語(yǔ)法。參考 JDBC 的 CallableStatement?
文檔以獲得更詳細(xì)的信息。?
16、就是iBatis中各種id的命名了,這個(gè)看起來(lái)小菜一碟,但是搞砸了會(huì)很痛苦。建議如果有DAO層的話,DAO接口的名字和SQL語(yǔ)句 id的名字保持一致。同時(shí),在DAO中將save和update封裝為一個(gè)方法(從Hibernate中學(xué)來(lái)的),這是非常好的。也可以直接在SQL層將插入和更新柔和在一塊,太復(fù)雜,有點(diǎn)影響效率,這見(jiàn)機(jī)行事了。?
?? 另外Spring提供了各種數(shù)據(jù)操作模板,通過(guò)模板,擦做數(shù)據(jù)也就是“一句話”的問(wèn)題,寫(xiě)個(gè)DAO還有必要么,尤其對(duì)iBatis來(lái)說(shuō),根本沒(méi)有必要。這樣,就需要在領(lǐng)域活動(dòng)層的設(shè)計(jì)上下功夫了。?
17 、iBatis的查詢也可以配置緩存策略,緩存的配置很復(fù)雜,分很多中情況,可以參看附件中的iBATIS-SqlMaps-2_cn.pdf 的39頁(yè)內(nèi)容,有詳細(xì)介紹。?
18、偷懶的最高境界,讓程序去干哪里80%的體力活。自己僅僅把把關(guān)。任何重復(fù)的活動(dòng)都有規(guī)律可循的,一旦發(fā)現(xiàn)了其中的規(guī)律,你就可以想辦法把自己從中解脫出來(lái)。?
??? iBatis也不例外,每個(gè)表都有增刪改查、分頁(yè)等操作。對(duì)應(yīng)在每個(gè)DAO方法上亦如此。可以通過(guò)數(shù)據(jù)庫(kù)生成sqlmap、entity、dao,然后將這些東西改吧改吧就完成大部分的工作量。本人已經(jīng)實(shí)現(xiàn)過(guò)了,當(dāng)然開(kāi)發(fā)這個(gè)工具的前提是你對(duì)iBatis有深入研究和理解。?
-------------------------------------------------?
下面是iBatis開(kāi)發(fā)指南中內(nèi)容:?
附錄:容易出錯(cuò)的地方?
本附錄是譯者添加的,列出了初學(xué)者容易出錯(cuò)的地方,作為完成快速入門課程后的學(xué)習(xí)?
筆記,可以讓初學(xué)者少走些彎路。僅供參考。?
1)? 在 parameterMap 和 resultMap 中,字段數(shù)據(jù)類型是 java.sql.Types 類定義的常量名?
稱。常用的數(shù)據(jù)類型包括 BLOB,CHAR,CLOB,DATE,LONGVARBINARY,?
INTEGER,NULL,NUMERIC,TIME,TIMESTAMP 和 VARCHAR 等。?
2)? 對(duì)于數(shù)據(jù)表中 NULLABLE 的字段,必須在 parameterMap 和 resultMap 中指定字段?
的數(shù)據(jù)類型。?
3)? 對(duì)于數(shù)據(jù)類型是 DATE,CLOB 或 BLOB 的字段,最好在 parameterMap 和 resultMap中指定數(shù)據(jù)類型。?
4)? 對(duì)于二進(jìn)制類型的數(shù)據(jù),可以將 LONGVARBINARY 映射成 byte[]。?
5)? 對(duì)于文本類型較大的數(shù)據(jù),可以將 CLOB 映射成 String。?
6) Java Bean 必須擁有缺省的構(gòu)造器(即無(wú)參數(shù)的構(gòu)造器)。?
7) Java Bean 最好實(shí)現(xiàn) Serializable 接口,以備應(yīng)用的進(jìn)一步擴(kuò)展。?
SqlMap的配置是iBatis中應(yīng)用的核心。這部分任務(wù)占據(jù)了iBatis開(kāi)發(fā)的70的工作量。?
1、命名空間:?
? <sqlMap namespace="Account">,在此空間外要引用此空間的元素,則需要加上命名空間名。?
2、實(shí)體的別名:?
? <typeAlias alias="Account" type="com.lavasoft.ibatissut.simple.domain.entity.Account"/>?
? 如果有用到的全名的地方,可以用別名代替,受命名空間約束。?
3、插入操作?
??? 對(duì)于自增主鍵的表,插入可以不配置插入的主鍵列。否則是必須的。?
4、獲取主鍵?
???? 插入語(yǔ)句之前配置:主要是針對(duì)Sequence主鍵而言,插入前必須指定一個(gè)主鍵值給要插入的記錄。Oracle、DB2亦如此,方法是在插入語(yǔ)句標(biāo)簽<insert....>之前配置上:?
??? <insert id="insertAccount" parameterClass="Account">?
??????? <selectKey resultClass="long" keyProperty="sctId">?
??????????? SELECT SEQ_TEST.NEXTVAL FROM DUAL?
??????? </selectKey>??
??????? insert into .... ........?
??? </insert>?
??
??? 插入語(yǔ)句之后配置:主要是針對(duì)自增主鍵的表而言,這類表在插入時(shí)不需要主鍵,而是在插入過(guò)程自動(dòng)獲取一個(gè)自增的主鍵。比如MySQL?
??? <insert id="insertAccount" parameterClass="Account">?
??????? <selectKey resultClass="long" keyProperty="sctId">?
??????????? SELECT LAST_INSERT_ID()?
?????? </selectKey>??
??????? insert into .... ........?
??? </insert>?
?? 當(dāng)然,是否需要配置<selectKey>根據(jù)情況,只要能保證記錄有主鍵即可。一旦配置了<selectKey>,就可以在執(zhí)行插入操作時(shí)獲取到新增記錄的主鍵。?
6、SQL入?yún)arameterClass?
? 插入語(yǔ)句入?yún)?#xff1a;parameterClass="類別名"? 來(lái)設(shè)定。?
? 查詢語(yǔ)句入?yún)?#xff1a;可以設(shè)定類別名,也可以設(shè)定為map,也可以設(shè)定為iBatis支持的原生類型(比如string、int、long等),當(dāng)只有一個(gè)原生類型入?yún)r(shí),使用#value#來(lái)引用,這個(gè)value是不是關(guān)鍵字,可變。比如:?
??? <select id="getById"? parameterClass="long" resultMap="result_base">?
??????? select * from customer where id = #value#?
??? </select>?
??? map是最強(qiáng)大的入?yún)⒎绞?#xff0c;任何入?yún)⒎绞蕉伎梢赞D(zhuǎn)換為這種入?yún)⒎绞?#xff0c;因?yàn)閕Batis僅接受一個(gè)入?yún)?#xff0c;當(dāng)幾個(gè)參數(shù)分布在不同對(duì)象中的時(shí)候,將這些對(duì)象的屬性(或者對(duì)象本身put)到map中,然后一次傳遞給sql語(yǔ)句是非常有效。可以自己寫(xiě)一個(gè)將對(duì)象或者對(duì)象集合轉(zhuǎn)換為map的工具(我已經(jīng)實(shí)現(xiàn)一個(gè)了)。?
??? 另外,map的中的元素(比如pobj)是個(gè)復(fù)雜對(duì)象,則還可以在SQL中以#pobj.protyename#的格式來(lái)引用其中內(nèi)嵌的屬性。當(dāng)然不推薦這么干。?
7、返回值參數(shù)類型?
????? 返回值參數(shù)也同樣有兩種類型,一種是對(duì)象類型resultClass="Account",一種是resultMap="AccountResult"。這兩種類型的選擇常常會(huì)令人迷惑不解,一言明其理:?
當(dāng)結(jié)果集列名和類屬性名完全對(duì)應(yīng)的時(shí)候,則應(yīng)該使用resultClass來(lái)指定查詢結(jié)果類型。當(dāng)然有些列明不對(duì)應(yīng),可以在sql中使用as重命名達(dá)到一致的效果。?
當(dāng)查詢結(jié)果列名和類屬性名對(duì)應(yīng)不上的時(shí)候,應(yīng)該選擇 resultMap指定查詢結(jié)果集類型。否則,則查詢出來(lái)填充的對(duì)象屬性為空(數(shù)字的為0,對(duì)象的為null)。?
但是實(shí)際上 resultMap是對(duì)一個(gè)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映射的結(jié)果的目的就是要將查詢的結(jié)果集綁定到映射對(duì)象的屬性上。?
?? 不管使用哪種返回值參數(shù)類型,其最終目的就是要把每條記錄映射到一個(gè)類的對(duì)象或者對(duì)象集合上,如果有某個(gè)類屬性映射不上,則在得到的這個(gè)對(duì)象或?qū)ο蠹现羞@個(gè)屬性為空。映射的屬性可以是表與實(shí)體中的一部分。不要同時(shí)使用兩種返回值參數(shù)類型,這樣只會(huì)令人迷惑。?
8、查詢結(jié)果集分組?
??? 查詢結(jié)果集排序有兩種方式:一是在結(jié)果集映射上定義<resultMap id="result" class="bar" groupBy="id">,另一種就是在SQL語(yǔ)句中分組。建議在SQL語(yǔ)句中分組,以獲得更大的可控制性。?
9、 SQL中參數(shù)的引用?
???? SQL中引用parameterClass的參數(shù)有三種方式:?
???? iBatis內(nèi)置支持的類型,比如int、string,使用#value#來(lái)引用,這個(gè)value是不是關(guān)鍵字,可變。?
???? map類型的參數(shù),使用#keyName#來(lái)引用,keyName為鍵名。?
???? 復(fù)雜對(duì)象的參數(shù),使用#propertyName#來(lái)引用,propertyName類屬性的名字。?
10、模糊查詢中參數(shù)的引用?
??? 模糊查詢是針對(duì)字符串而言的,如果遇到兩個(gè)單引號(hào)要包含一個(gè)參數(shù),則不能再用#來(lái)引用變量了,而應(yīng)該改為$,比如:'%$varName$%',當(dāng)然,也可以使用 '%' || #varname# || '%' 來(lái)繞過(guò)此問(wèn)題。?
11、SQL片段?
?????? 可以通過(guò)<sql id="sql_xxx">...</sql>定義SQL片段,然后<include refid="sql_xxx"/>來(lái)在各種語(yǔ)句中引用,達(dá)到復(fù)用目的。?
12、動(dòng)態(tài)SQL?
????? 可以通過(guò)使用動(dòng)態(tài)SQL來(lái)組織靈活性更大的更通用的SQL,這樣極大減少了編碼量,是iBatis應(yīng)用的第二大亮點(diǎn)。?
???? 比如:一個(gè)動(dòng)態(tài)的where條件?
??????????????? <dynamic prepend="where">?
??????????????????????? <isNotEmpty prepend="and" property="$$$$$">?
??????????????????????????????? $name like '%'|| #$name# ||'%'?
??????????????????????? </isNotEmpty>?
??????????????????????? <isGreaterThan prepend="and" property="$$$$$" compareValue="$$$number">?
??????????????????????????????? $code like '%'|| #$code# ||'%'?
??????????????????????? </isGreaterThan>?
??????????????? </dynamic>?
???? 當(dāng)然,prepend表示鏈接關(guān)鍵字,可以為任何字符串,當(dāng)為sql關(guān)鍵字時(shí),iBatis自動(dòng)判斷是否應(yīng)該添加該關(guān)鍵字。該語(yǔ)法也很簡(jiǎn)單,關(guān)鍵是要會(huì)用心思考組織動(dòng)態(tài)SQL。?
??? 這里面有一點(diǎn)要注意:區(qū)別<isNotEmpty>和<isNotNull>區(qū)別,當(dāng)為空空串時(shí)<isNotEmpty>返回true,當(dāng)為空串時(shí)<isNotNull>返回真。哈哈,自己體會(huì)吧,說(shuō)了反而啰嗦。?
13、結(jié)果集映射繼承?
結(jié)果集映射的繼承的目的是為了映射定義的復(fù)用,比如下面定義了兩個(gè)映射,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>?
這樣,就很容易擴(kuò)展了一個(gè)映射策略。?
???????
14、查詢注入?
查詢注入是在一個(gè)查詢中嵌入另外一個(gè)查詢,這樣做的目的是為了實(shí)現(xiàn)實(shí)體對(duì)象之間的關(guān)聯(lián)關(guān)聯(lián)關(guān)系(一對(duì)一、一對(duì)多、多對(duì)多)分單項(xiàng)雙向。有關(guān)這些內(nèi)容,是比較復(fù)雜的,筆者對(duì)此做了深入研究,并分別寫(xiě)了三篇來(lái)講述。?
查詢注入的實(shí)現(xiàn)就是在實(shí)體屬性為另外一個(gè)實(shí)體或者實(shí)體集合的時(shí)候,引入一個(gè)相關(guān)的查詢來(lái)實(shí)現(xiàn),例如,客戶和訂單的映射關(guān)系:?
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>?
在這個(gè)映射中,為了查詢客戶的時(shí)候,能查詢到相關(guān)的訂單,可以在映射orderlist 屬性的時(shí)候,將其指向另外一個(gè)查詢orders.findByCustomerId ,這個(gè)查詢是以Customer的id 為參數(shù)來(lái)查詢的。?
select="orders.findByCustomerId " 這個(gè)查詢定義如下:?
??? <select id="findByCustomerId" resultMap="result_base" parameterClass="long">?
??????? select * from orders where customerId = #value#?
??? </select>?
原理就是這么簡(jiǎn)單,然后根據(jù)實(shí)際情況,可以自由實(shí)現(xiàn)實(shí)體間的關(guān)聯(lián)關(guān)系。?
14、iBatis的分頁(yè)查詢?
iBatis 的分頁(yè)有兩種方式,一點(diǎn)都不神秘,不要被網(wǎng)上的流言所迷惑。?
第一種方式:結(jié)果集篩選分頁(yè)。先執(zhí)行部分頁(yè)的SQL查詢語(yǔ)句,然后得到一個(gè) ResultSet,然后根據(jù)分頁(yè)范圍選擇有效的記錄填充到對(duì)象中,最終以集合的形式返回。對(duì)于10w條一下的記錄的表,不存在性能問(wèn)題,如果存在,你可以選擇第二中方式。?
第二種方式:SQL分頁(yè),通過(guò)組裝分頁(yè)類型的SQL來(lái)實(shí)現(xiàn)分頁(yè)。這個(gè)關(guān)鍵在于分頁(yè)參數(shù)的傳遞和分頁(yè)SQL的構(gòu)建。分頁(yè)SQL構(gòu)件每種數(shù)據(jù)庫(kù)都不一樣,不說(shuō)了。分頁(yè)參數(shù)的傳遞卻可以通用。我主張用map分裝入?yún)?#xff0c;連同分頁(yè)參數(shù)一塊傳遞進(jìn)來(lái),就搞定了。如果原來(lái)沒(méi)有考慮到分頁(yè),而用的是對(duì)象做參數(shù),則可以通過(guò)apache 的 beanutils組件來(lái)實(shí)現(xiàn)一個(gè)object到map之間的轉(zhuǎn)換工具,問(wèn)題迎刃而解。?
當(dāng)然,這還不是分頁(yè)查詢應(yīng)用的最高境界。思考,分頁(yè)需要計(jì)算一個(gè)總記錄數(shù),記錄數(shù)執(zhí)行的sql返回值是count(?),條件是除了分頁(yè)以外的條件,因此應(yīng)該將查詢SQL靜態(tài)分開(kāi),以MySQL為例,可以將查詢分為查什么,和什么條件兩部分,在條件部分對(duì)分頁(yè)參數(shù)進(jìn)行動(dòng)態(tài)判斷,如果分頁(yè)參數(shù)就不分頁(yè),如果有則分頁(yè)。這樣最后只需要兩個(gè)組裝的sql就可以計(jì)算總數(shù)和分頁(yè)查詢了。大大簡(jiǎn)化了問(wèn)題的難度。 Oracle的解決思路也一樣,不一樣的地方就是拼裝分頁(yè)SQL改變了。?
15、執(zhí)行存儲(chǔ)過(guò)程的配置?
SQL Map 通過(guò)<procedure>元素支持存儲(chǔ)過(guò)程。下面的例子說(shuō)明如何使用具有輸出參數(shù)?
的存儲(chǔ)過(guò)程。?
??? <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>?
調(diào)用上面的存儲(chǔ)過(guò)程將同時(shí)互換兩個(gè)字段(數(shù)據(jù)庫(kù)表)和參數(shù)對(duì)象(Map)中的兩個(gè) email地址。如果參數(shù)的 mode 屬性設(shè)為 INOUT 或 OUT,則參數(shù)對(duì)象的值被修改。否則保持不變。?
注意!要確保始終只使用 JDBC 標(biāo)準(zhǔn)的存儲(chǔ)過(guò)程語(yǔ)法。參考 JDBC 的 CallableStatement?
文檔以獲得更詳細(xì)的信息。?
16、就是iBatis中各種id的命名了,這個(gè)看起來(lái)小菜一碟,但是搞砸了會(huì)很痛苦。建議如果有DAO層的話,DAO接口的名字和SQL語(yǔ)句 id的名字保持一致。同時(shí),在DAO中將save和update封裝為一個(gè)方法(從Hibernate中學(xué)來(lái)的),這是非常好的。也可以直接在SQL層將插入和更新柔和在一塊,太復(fù)雜,有點(diǎn)影響效率,這見(jiàn)機(jī)行事了。?
?? 另外Spring提供了各種數(shù)據(jù)操作模板,通過(guò)模板,擦做數(shù)據(jù)也就是“一句話”的問(wèn)題,寫(xiě)個(gè)DAO還有必要么,尤其對(duì)iBatis來(lái)說(shuō),根本沒(méi)有必要。這樣,就需要在領(lǐng)域活動(dòng)層的設(shè)計(jì)上下功夫了。?
17 、iBatis的查詢也可以配置緩存策略,緩存的配置很復(fù)雜,分很多中情況,可以參看附件中的iBATIS-SqlMaps-2_cn.pdf 的39頁(yè)內(nèi)容,有詳細(xì)介紹。?
18、偷懶的最高境界,讓程序去干哪里80%的體力活。自己僅僅把把關(guān)。任何重復(fù)的活動(dòng)都有規(guī)律可循的,一旦發(fā)現(xiàn)了其中的規(guī)律,你就可以想辦法把自己從中解脫出來(lái)。?
??? iBatis也不例外,每個(gè)表都有增刪改查、分頁(yè)等操作。對(duì)應(yīng)在每個(gè)DAO方法上亦如此。可以通過(guò)數(shù)據(jù)庫(kù)生成sqlmap、entity、dao,然后將這些東西改吧改吧就完成大部分的工作量。本人已經(jīng)實(shí)現(xiàn)過(guò)了,當(dāng)然開(kāi)發(fā)這個(gè)工具的前提是你對(duì)iBatis有深入研究和理解。?
-------------------------------------------------?
下面是iBatis開(kāi)發(fā)指南中內(nèi)容:?
附錄:容易出錯(cuò)的地方?
本附錄是譯者添加的,列出了初學(xué)者容易出錯(cuò)的地方,作為完成快速入門課程后的學(xué)習(xí)?
筆記,可以讓初學(xué)者少走些彎路。僅供參考。?
1)? 在 parameterMap 和 resultMap 中,字段數(shù)據(jù)類型是 java.sql.Types 類定義的常量名?
稱。常用的數(shù)據(jù)類型包括 BLOB,CHAR,CLOB,DATE,LONGVARBINARY,?
INTEGER,NULL,NUMERIC,TIME,TIMESTAMP 和 VARCHAR 等。?
2)? 對(duì)于數(shù)據(jù)表中 NULLABLE 的字段,必須在 parameterMap 和 resultMap 中指定字段?
的數(shù)據(jù)類型。?
3)? 對(duì)于數(shù)據(jù)類型是 DATE,CLOB 或 BLOB 的字段,最好在 parameterMap 和 resultMap中指定數(shù)據(jù)類型。?
4)? 對(duì)于二進(jìn)制類型的數(shù)據(jù),可以將 LONGVARBINARY 映射成 byte[]。?
5)? 對(duì)于文本類型較大的數(shù)據(jù),可以將 CLOB 映射成 String。?
6) Java Bean 必須擁有缺省的構(gòu)造器(即無(wú)參數(shù)的構(gòu)造器)。?
7) Java Bean 最好實(shí)現(xiàn) Serializable 接口,以備應(yīng)用的進(jìn)一步擴(kuò)展。?
本人認(rèn)為:盡量避免在每個(gè)入?yún)⒑竺娓郊訁?shù)的類型。以保持配置簡(jiǎn)潔,并且本人在長(zhǎng)期開(kāi)發(fā)中,沒(méi)有發(fā)現(xiàn)必須要那么做。
轉(zhuǎn)載:http://zhuyuehua.iteye.com/blog/1003297
總結(jié)
以上是生活随笔為你收集整理的iBatis SqlMap的配置总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: jQuery表单校验jquery.val
- 下一篇: Oracle中TO_DATE格式的使用小