版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
動態(tài)SQL語句主要元素使用動態(tài)SQL語句實現(xiàn)多條件查詢使用動態(tài)SQL語句實現(xiàn)更新使用<foreach>元素實現(xiàn)復(fù)雜查詢使用<bind>元素實現(xiàn)SQL語句拼接第3章
動態(tài)SQL語句2024/1/29回顧與作業(yè)點評2MyBatis基本要素核心對象SqlSessionFactoryBuilderSqlSessionFactorySqlSession通過SqlSession實例直接運行映射的SQL語句基于mapper接口的方式執(zhí)行SQL語句系統(tǒng)核心配置文件propertiestypeAliasesenvironmentsmappersSQL映射文件核心對象最佳生命周期最佳作用域SqlSessionFactoryBuilder方法體內(nèi)方法體內(nèi)(局部變量)SqlSessionFactory從應(yīng)用服務(wù)啟動開始一直到應(yīng)用服務(wù)停止—application整個應(yīng)用內(nèi)SqlSession一次請求的有效期一次請求的有效期內(nèi)回顧作業(yè)點評點評作業(yè)的提交情況和共性問題學(xué)習(xí)目標(biāo)/Target3
了解動態(tài)SQL語句中的主要元素及其說明掌握動態(tài)SQL語句中主要元素的使用方法
熟練掌握動態(tài)SQL語句的運用章節(jié)概述/Summary4在實際項目的開發(fā)中,開發(fā)人員在使用JDBC或其他持久層框架進(jìn)行開發(fā)時,經(jīng)常需要根據(jù)不同的條件拼接SQL語句,拼接SQL語句時還要確保不能遺漏必要的空格、標(biāo)點符號等,這種編程方式給開發(fā)人員帶來了非常大的不便,而MyBatis提供的SQL語句動態(tài)組裝功能,恰能很好的解決這一問題。本章將對MyBatis框架的動態(tài)SQL進(jìn)行詳細(xì)講解。
目錄/CONTENTS動態(tài)SQL語句主要元素使用<foreach>元素實現(xiàn)復(fù)雜查詢使用動態(tài)SQL語句實現(xiàn)更新使用動態(tài)SQL語句實現(xiàn)多條件查詢5使用<bind>元素實現(xiàn)SQL語句拼接14325動態(tài)SQL語句
主要元素01第3章動態(tài)SQL語句動態(tài)SQL有什么作用?動態(tài)SQL中的元素7
開發(fā)人員在使用JDBC或其他類似的框架進(jìn)行數(shù)據(jù)庫開發(fā)時,通常都要根據(jù)需求去手動拼裝SQL,這是一個非常麻煩且痛苦的工作,而MyBatis提供的對SQL語句動態(tài)組裝的功能,恰能很好的解決這一麻煩工作。STEP01
動態(tài)SQL是MyBatis的強大特性之一,MyBatis采用了功能強大的基于OGNL(ObjectGraphNavigationLanguage)的表達(dá)式來完成動態(tài)SQL。在MyBatis的映射文件中,開發(fā)人員可通過動態(tài)SQL元素靈活組裝SQL語句,這在很大程度上避免了單一SQL語句的反復(fù)堆砌,提高了SQL語句的復(fù)用性。STEP03使用動態(tài)SQL的好處動態(tài)SQL中的元素8動態(tài)SQL中的元素9
動態(tài)SQL是MyBatis的強大特性之一,MyBatis3采用了功能強大的基于OGNL的表達(dá)式來完成動態(tài)SQL。動態(tài)SQL主要元素如下表所示:SQL元素說明<if>判斷語句,用于單條件分支判斷<choose>(<when>、<otherwise>)相當(dāng)于Java中的switch...case...default語句,用于多條件分支判斷<where>簡化SQL語句中where的條件判斷。<trim>可以靈活地去除多余的關(guān)鍵字。<set>解決動態(tài)更新語句。<foreach>循環(huán)語句,常用于in語句等列舉條件中<bind>從OGNL表達(dá)式中創(chuàng)建一個變量,并將其綁定到上下文,常用于模糊查詢的sql中動態(tài)SQL10基于OGNL表達(dá)式完成多條件查詢等邏輯實現(xiàn)用于實現(xiàn)動態(tài)SQL的元素主要有iftrimwheresetchoose(when、otherwise)foreach使用動態(tài)SQL語句實現(xiàn)多條件查詢02第3章動態(tài)SQL語句STEP01
在MyBatis中,<if>元素是最常用的判斷元素,它類似于Java中的if語句,主要用于實現(xiàn)某些簡單的條件判斷。在實際應(yīng)用中,我們可能會通過某個條件查詢某個數(shù)據(jù)。例如,要查找某個客戶的信息,可以通過姓名或者年齡來查找客戶,也可以不填寫年齡直接通過姓名來查找客戶,還可以都不填寫而查詢出所有客戶,此時姓名和年齡就是非必須條件。類似于這種情況,在MyBatis中就可以通過<if>元素來實現(xiàn)。STEP03<if>元素的應(yīng)用<if>元素12<if>元素13
在MyBatis中,<if>元素是最常用的判斷語句,它類似于Java中的if語句,主要用于實現(xiàn)某些簡單的條件選擇。其基本使用示例如下:select*fromtb_userwhere1=1<iftest="username!=nullandusername!=''"> andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''"> andjobs=#{jobs}</if>使用<if>元素對username和jobs進(jìn)行非空判斷,并動態(tài)組裝SQL<if>元素14需求說明改造查詢用戶信息列表的演示示例,增加查詢條件用戶角色(根據(jù)角色id查詢)用戶名稱(模糊查詢)演示示例:改造用戶表的查詢操作-多條件查詢<if>元素15當(dāng)傳入用戶角色參數(shù)為空的時候,檢索結(jié)果為空?正確結(jié)果所有用戶角色下的用戶數(shù)據(jù)原因如何處理if(判斷參數(shù)):實現(xiàn)簡單的條件判斷問題分析select*fromtb_useru,tb_roler whereu.userRole=r.idandu.userNamelikeCONCAT(‘%’,‘’,‘%’) andu.userRole=null;演示示例
:改造用戶表的查詢操作-if<where>元素16當(dāng)只傳入?yún)?shù):用戶角色,而不傳入?yún)?shù):用戶名稱的時候,控制臺報SQL異常錯誤?正確結(jié)果指定用戶角色下的所有用戶數(shù)據(jù)原因如何處理where問題分析select*fromtb_userwhereanduserRole=?<where>元素17where簡化SQL語句中where條件判斷智能處理and和or演示示例:改造用戶表的查詢操作-if+where改造訂單表查詢(if)18需求說明改造訂單表的查詢功能,使用動態(tài)SQL完善此功能查詢條件商品名稱(模糊查詢)供應(yīng)商id是否付款查詢結(jié)果列列表訂單id、訂單編碼、商品名稱、供應(yīng)商id、供應(yīng)商名稱、訂單金額、是否付款、創(chuàng)建時間修改SQL語句–使用if完成時間:15分鐘練習(xí)指導(dǎo)改造供應(yīng)商表查詢(if+where)19需求說明改造供應(yīng)商表的查詢功能,使用動態(tài)SQL完善此功能查詢條件供應(yīng)商編碼(模糊查詢)供應(yīng)商名稱(模糊查詢)查詢結(jié)果列列表供應(yīng)商id、供應(yīng)商編碼、供應(yīng)商名稱、聯(lián)系人、聯(lián)系電話、傳真、創(chuàng)建時間修改SQL語句–使用if+where組合完成時間:15分鐘練習(xí)指導(dǎo)共性問題集中講解20常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解
<trim>元素用于刪除多余的關(guān)鍵字,它可以直接實現(xiàn)<where>元素的功能。<trim>元素包含4個屬性。
<trim>元素
21屬性說明prefix
指定給SQL語句增加的前綴prefixOverrides
指定SQL語句中要去掉的前綴字符串suffix
指定給SQL語句增加的后綴suffixOverrides
指定SQL語句中要去掉的后綴字符串<trim>元素22trim屬性prefixsuffixprefixOverridessuffixOverrides更靈活地去除多余關(guān)鍵字替代where和set<selectid="getUserList5"resultType="User"> select*fromtb_user
<trimprefix="where"prefixOverrides="and|or"> <iftest="userName!=nullanduserName!=''"> anduserNamelikeCONCAT('%',#{userName},'%') </if> <iftest="userRole!=null"> anduserRole=#{userRole} </if> </trim></select>
上述配置代碼中,<trim>元素的作用是去除一些多余的前綴字符串,它的prefix屬性代表的是語句的前綴(where),而prefixOverrides屬性代表的是需要去除的前綴字符串(SQL中的“AND”或“OR”)。
<where>、<trim>元素23
在前兩個小節(jié)的案例中,映射文件中編寫的SQL后面都加入了“where1=1”的條件,那么到底為什么要這么寫呢?如果將where后“1=1”的條件去掉,那么MyBatis所拼接出來的SQL將會如下所示:select*fromtb_userwhereandusernamelikeconcat('%',?,'%')
可以看出上面SQL語句明顯存在SQL語法錯誤,而加入了條件“1=1”后,既保證了where后面的條件成立,又避免了where后面第一個詞是and或者or之類的關(guān)鍵詞。不過“where1=1”這種寫法對于初學(xué)者來將不容易理解,并且也不夠雅觀。<where>、<trim>元素24select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>
針對上述情況中“where1=1”,在MyBatis的SQL中就可以使用<where>或<trim>元素進(jìn)行動態(tài)處理。<where>會自動判斷SQL語句,只有<where>內(nèi)的條件成立時,才會在拼接SQL中加入where關(guān)鍵字,否則將不會添加;還會去除多余的“AND”或“OR”。<where>元素處理<trim>元素處理<trim>的作用是去除特殊的字符串,它的prefix屬性代表語句的前綴,prefixOverrides屬性代表需要去除的哪些特殊字符串,功能和<where>基本是等效的。動態(tài)SQL處理“where1=1”select*fromtb_user<where><iftest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''">andjobs=#{jobs}</if></where>select*fromtb_user<trimprefix="where"prefixOverrides="and"><iftest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</if><iftest="jobs!=nullandjobs!=''">andjobs=#{jobs}</if></trim>STEP01
在使用<if>元素時,只要test屬性中的表達(dá)式為true,就會執(zhí)行元素中的條件語句,但是在實際應(yīng)用中,有時只需要從多個選項中選擇一個去執(zhí)行。
例如下面的場景:“當(dāng)客戶名稱不為空,則只根據(jù)客戶名稱進(jìn)行客戶篩選;當(dāng)客戶名稱為空,而客戶職業(yè)不為空,則只根據(jù)客戶職業(yè)進(jìn)行客戶篩選。當(dāng)客戶名稱和客戶職業(yè)都為空,則要求查詢出所有電話不為空的客戶信息?!?/p>
針對上面情況,使用<if>元素進(jìn)行處理是不合適的。MyBatis提供了<choose>、<when>、<otherwise>元素進(jìn)行處理,這三個元素往往組合在一起使用,作用相當(dāng)于Java語言中的if…elseif…else。STEP03<choose><when>otherwise>使用場景<choose>、<when>、<otherwise>元素25<choose>、<when>、<otherwise>元素26“當(dāng)客戶名稱不為空,則只根據(jù)客戶名稱進(jìn)行客戶篩選;
當(dāng)客戶名稱為空,而客戶職業(yè)不為空,則只根據(jù)客戶職業(yè)進(jìn)行客戶篩選。
當(dāng)客戶名稱和客戶職業(yè)都為空,則要求查詢出所有電話不為空的客戶信息。”假設(shè)如下場景:
這種情況下,使用<if>元素進(jìn)行處理是非常不合適的。如果使用的是Java語言,這種情況顯然更適合使用switch…case…default語句來處理,而在SQL中就可以使用<choose>、<when>、<otherwise>元素組合進(jìn)行處理。其基本使用示例如代碼所示:select*fromtb_userwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>使用<choose>及其子元素依次對條件進(jìn)行非空判斷,并動態(tài)組裝SQLchoose(when、otherwise)27choose(when、otherwise)相當(dāng)于Java中switch語句當(dāng)when有條件滿足的時候,就跳出choose演示示例:改造用戶表的查詢操作-choose<choose> <whentest="條件1">…</when> <whentest="條件2">…</when> <whentest="條件3">…</when> … <otherwise>…</otherwise></choose> 改造供應(yīng)商列表查詢-choose28需求說明實現(xiàn)按條件查詢供應(yīng)商表,查詢條件如下供應(yīng)商編碼(模糊查詢)供應(yīng)商名稱(模糊查詢)供應(yīng)商聯(lián)系人(模糊查詢)創(chuàng)建時間在本年內(nèi)(時間范圍)查詢結(jié)果列顯示:供應(yīng)商id、供應(yīng)商編碼、供應(yīng)商名稱、供應(yīng)商聯(lián)系人、創(chuàng)建時間choose(when、otherwise)完成時間:15分鐘練習(xí)指導(dǎo)共性問題集中講解29常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解使用動態(tài)SQL語句實現(xiàn)更新03第3章動態(tài)SQL語句<set>元素使用場景
在Hibernate框架中,如果想要更新某一個對象,就需要發(fā)送所有的字段給持久化對象,然而在實際應(yīng)用中,大多數(shù)情況下都是更新某一個或幾個字段。如果更新的每一條數(shù)據(jù)都要將其所有的屬性都更新一遍,那么執(zhí)行效率是非常差的。為了解決更新數(shù)據(jù)的效率問題,MyBatis提供了<set>元素。<set>元素主要用于更新操作,它可以在動態(tài)SQL語句前輸出一個SET關(guān)鍵字,并將SQL語句中最后一個多余的逗號去除。<set>元素與<if>元素結(jié)合可以只更新需要更新的字段。
更新操作31<set>元素32select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>
在Hibernate中,想要更新某個對象,就需要發(fā)送所有的字段給持久化對象,這種想更新的每一條數(shù)據(jù)都要將其所有的屬性都更新一遍的方法,其執(zhí)行效率是非常差的。為此,在MyBatis中可以使用動態(tài)SQL中的<set>元素進(jìn)行處理:<updateid="update"parameterType=“User">updatetb_user<set><iftest="username!=nullandusername!=''">username=#{username},</if><iftest="jobs!=nullandjobs!=''">jobs=#{jobs},</if></set>whereid=#{id}</update>使用<set>和<if>元素對username和jobs進(jìn)行更新判斷,并動態(tài)組裝SQL。這樣就只需要傳入想要更新的字段即可<set>元素字段非空
在映射文件中使用<set>元素和<if>元素組合進(jìn)行update語句動態(tài)SQL組裝時,如果<set>元素內(nèi)包含的內(nèi)容都為空,則會出現(xiàn)SQL語法錯誤。因此,在使用<set>元素進(jìn)行字段信息更新時,要確保傳入的更新字段不能都為空。更新操作33set34更新用戶表數(shù)據(jù)時,若某個參數(shù)為null時,會導(dǎo)致更新錯誤正確結(jié)果若某個參數(shù)為null,則不需要更新,保持?jǐn)?shù)據(jù)庫原值原因SQL語句如何處理ifset演示示例:改造用戶表的修改操作-if+set指導(dǎo)注意技能訓(xùn)練—改造供應(yīng)商表修改操作(if+set)35需求說明改造供應(yīng)商表的修改功能,使用動態(tài)SQL完善此功能修改SQL語句–使用if+set組合完成時間:15分鐘練習(xí)指導(dǎo)共性問題集中講解36常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解使用<trim>元素更新
除了使用<set>元素外,還可以通過<trim>元素來實現(xiàn)更新操作。其中,<trim>元素的prefix屬性指定要添加的<trim>元素所包含內(nèi)容的前綴為set,suffixOverrides屬性指定去除的<trim>元素所包含內(nèi)容的后綴為逗號。更新操作37trim38if+trim使用if+trim替代if+set進(jìn)行更新用戶表數(shù)據(jù),效果一樣演示示例:改造用戶表的修改操作-if+trim<updateid="modify"parameterType="User">updatetb_user<trimprefix="set"suffixOverrides=","suffix="whereid=#{id}"> <iftest="userCode!=null">userCode=#{userCode},</if> <iftest="userName!=null">userCode=#{userName},</if> <iftest="userPassword!=null">userPassword=#{userPassword},</if></trim></update>示例改造供應(yīng)商表修改操作(if+trim)39需求說明改造供應(yīng)商表的修改功能,使用動態(tài)SQL完善此功能修改SQL語句–使用if+trim組合完成時間:15分鐘練習(xí)指導(dǎo)共性問題集中講解40常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解使用<foreach>元素實現(xiàn)復(fù)雜查詢04第3章動態(tài)SQL語句<foreach>元素42select*fromt_customerwhere1=1<choose><whentest="username!=nullandusername!=''">andusernamelikeconcat('%',#{username},'%')</when><whentest="jobs!=nullandjobs!=''">andjobs=#{jobs}</when><otherwise>andphoneisnotnull</otherwise></choose>
在一個客戶表中有1000條數(shù)據(jù),現(xiàn)在需要將id值小于100的客戶信息全部查詢出來,這要怎么做呢?假設(shè)如下需求:一條一條的查詢1在Java中用for循環(huán)查詢2那如果要查詢1000條數(shù)據(jù)呢,豈不是很累?考慮過N條查詢語句時的查詢效率了嗎?<foreach>元素43foreach迭代一個集合,通常用于in條件屬性itemindexcollection:必須指定listarraymap-keyopenseparatorclose<foreach>元素的屬性
44屬性說明item
表示集合中每一個元素進(jìn)行迭代時的別名。該屬性為必選。index在List和數(shù)組中,index是元素的序號,在Map中,index是元素的key。該屬性可選。open
表示foreach語句代碼的開始符號,一般和close=“)”合用。常用在in條件語句中。該屬性可選。separator
表示元素之間的分隔符,例如,在條件語句中,separator=“,”會自動在元素中間用“,”隔開,避免手動輸入逗號導(dǎo)致SQL錯誤,錯誤示例如in(1,2,)。該屬性可選。close表示foreach語句代碼的關(guān)閉符號,一般和open="("合用。常用在in條件語句中。該屬性可選。collection用于指定遍歷參數(shù)的類型。注意,該屬性必須指定,不同情況下,該屬性的值是不一樣的。
<foreach>元素45需求說明:指定用戶角色(1-n個),獲取這些用戶角色下的用戶列表信息查詢SQL語句含有in條件使用foreach實現(xiàn)參數(shù):用戶角色列表參數(shù)類型:數(shù)組演示示例:獲取指定用戶角色下用戶列表-foreach_array分析select*fromtb_user whereuserRolein(參數(shù)1,參數(shù)2,參數(shù)3…);<foreach>元素46
針對上述需求,理想的解決方法就是使用MyBatis中動態(tài)SQL的<foreach>元素進(jìn)行處理。其基本使用示例如下所示:<selectid="findUserByIds"parameterType="List"resultType=“User">select*fromtb_userwhereidin<foreachitem="id"index="index"collection="list"open="("separator=","close=")">#{id}</foreach></select><foreach>元素47
關(guān)于上述示例中<foreach>元素中使用的幾種屬性的描述具體如下:<foreach>主要屬性item:配置的是循環(huán)中當(dāng)前的元素。collection:配置的list是傳遞過來的參數(shù)類型(首字母小寫),它可以是一個array、list(或collection)、Map集合的鍵、POJO包裝類中數(shù)組或集合類型的屬性名等。index:配置的是當(dāng)前元素在集合的位置下標(biāo)。separator:配置的是各個元素的間隔符。open和close:配置的是以什么符號將這些集合元素包裝起來。在遍歷參數(shù)時,<collection>屬性的值是必須指定的。不同情況下,該屬性的取值也是不一樣的,主要有以下三種情況。List類型
若入?yún)閱螀?shù)且參數(shù)類型是一個List,collection屬性值為list。數(shù)組類型若入?yún)閱螀?shù)且參數(shù)類型是一個數(shù)組,collection屬性值為array。Map類型
若傳入?yún)?shù)為多參數(shù),就需要把參數(shù)封裝為一個Map進(jìn)行處理,collection屬性值為Map。<collection>屬性的取值48<foreach>元素49
在使用<foreach>時最關(guān)鍵也是最容易出錯的就是collection屬性,該屬性是必須指定的,而且在不同情況下,該屬性的值是不一樣的。主要有以下3種情況:如果傳入的是單參數(shù)且參數(shù)類型是一個數(shù)組或者List的時候,collection屬性值分別為array和list(或collection)。1如果傳入的參數(shù)是多個的時候,就需要把它們封裝成一個Map了,當(dāng)然單參數(shù)也可以封裝成Map集合,這時候collection屬性值就為Map的鍵。2如果傳入的參數(shù)是POJO包裝類的時候,collection屬性值就為該包裝類中需要進(jìn)行遍歷的數(shù)組或集合的屬性名。3<foreach>元素50需求說明:改造上一個演示示例,使用foreach實現(xiàn),參數(shù)類型改為List演示示例:獲取指定用戶角色下用戶列表-foreach_list獲取指定供應(yīng)商列表下的訂單列表51需求說明指定供應(yīng)商列表(1-n個),獲取這些供應(yīng)商下的訂單列表信息要求使用foreach實現(xiàn),參數(shù)類型為數(shù)組完成之后,把參數(shù)類型改為List實現(xiàn)此功能完成時間:20分鐘練習(xí)共性問題集中講解52常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解<foreach>元素53需求說明:在上一個演示示例中,增加一個參數(shù):gender,要求查詢出指定性別和用戶角色列表下的用戶列表多參數(shù)封裝成Map單參數(shù)也可封裝成Map嗎?演示示例:獲取多參數(shù)下用戶列表-foreach_map分析問題思考獲取多參數(shù)下的訂單列表54需求說明:根據(jù)訂單編碼(模糊查詢),指定供應(yīng)商列表(1-n個),獲取相應(yīng)的訂單列表信息多參數(shù)封裝成Map完成時間:30分鐘練習(xí)指導(dǎo)共性問題集中講解55常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解使用<bind>元素實現(xiàn)SQL語句拼接05第3章動態(tài)SQL語句<bind>元素57
還記得入門案例中模糊查詢的SQL語句么?select*fromtb_userwhereusernamelike'%${value}%'上述SQL語句有什么不妥?2如果使用“${}”進(jìn)行字符串拼接,則無法防止SQL注入問題;如果改用concat函數(shù)進(jìn)行拼接,則只針對MySQL數(shù)據(jù)庫有效;3如果改用“||”進(jìn)行字符串拼接,則只針對Oracle數(shù)據(jù)庫有效。1小提示:這樣,映射文件中的SQL就要根據(jù)不同的情況提供不同形式的實現(xiàn),這顯然是比較麻煩的,且不利于項目的移植。為了減少這種麻煩,就可以使用MyBatis的<bind>元素來解決這一問題。<bind>元素58MyBatis的<bind>元素可以通過OGNL表達(dá)式來創(chuàng)建一個上下文變量,其使用方式如下:<!--<bind>元素的使用:根據(jù)用戶名模糊查詢用戶信息--><selectid="findUserByName"parameterType="User"resultType="User"> <!--_parameter.getUsername()也可直接寫成傳入的字段屬性名,即username--> <bindname="pattern_username"value="'%'+_parameter.getUserName()+'%'"/> select*fromtb_user whereusernamelike#{pattern_username}</select>_parameter.getUsername()表示傳遞進(jìn)來的參數(shù)(也可以直接寫成對應(yīng)的參數(shù)變量名,如username)需要的地方直接引用<bind>元素的name屬性值即可本章小結(jié)
本章主要講解了動態(tài)SQL相關(guān)知識。首先講解了動態(tài)SQL中的元素;其次講解了條件查詢操作,包括<if>元素、<choose>元素、<when>元素、<otherwise>元素、<where>元素和<trim>元素的使用;然后講解了更新操作;最后講解了復(fù)雜查詢操作。通過本章的學(xué)習(xí),讀者可以了解常用動態(tài)SQL元素的主要作用,并能夠掌握這些元素在實際開發(fā)中的應(yīng)用。在MyBatis框架中,這些動態(tài)SQL元素十分重要,熟練的掌握它們能夠極大地提高開發(fā)效率。
本章小結(jié)59總結(jié)60if+setif-whereif+trimchoose(when、otherwise)foreachMyBatis-動態(tài)SQLitemidexcollectionopenseparatorcloselistarraymap本章作業(yè)?
本章作業(yè)請簡述MyBatis框架動態(tài)SQL中的主要元素及其作用。請簡述MyBatis框架動態(tài)SQL中<foreach>元素collection屬性的注意事項。?預(yù)習(xí)作業(yè)不同對象之間有哪幾種關(guān)聯(lián)方式?MyBatis關(guān)聯(lián)查詢的方式有哪些?61問題及作業(yè)集中問題&課后作業(yè)62關(guān)聯(lián)映射一對一一對多多對多<resultMap>元素自動映射級別第4章
MyBatis的關(guān)聯(lián)映射2024/1/29學(xué)習(xí)目標(biāo)/Target64了解表之間及對象之間的關(guān)聯(lián)關(guān)系熟悉關(guān)聯(lián)關(guān)系中的嵌套查詢和嵌套結(jié)果掌握一對一、一對多和多對多關(guān)聯(lián)映射的使用方法章節(jié)概述/Summary65通過前面幾章介紹了MyBatis的基本用法、關(guān)聯(lián)映射和動態(tài)SQL等重要知識,但這些知識只是針對單表實現(xiàn)進(jìn)行操作的,在實際開發(fā)中,對數(shù)據(jù)庫的操作常常會涉及到多張表,針對多表之間的操作,MyBatis提供了關(guān)聯(lián)映射,通過關(guān)聯(lián)映射可以很好地處理表與表、對象與對象之間的關(guān)聯(lián)關(guān)系。此外,在實際開發(fā)中經(jīng)常需要合理地利用MyBatis緩存來加快數(shù)據(jù)庫查詢,進(jìn)而有效地提升數(shù)據(jù)庫性能。本章將對MyBatis的關(guān)聯(lián)映射以及MyBatis緩存機制進(jìn)行詳細(xì)講解。
目錄/CONTENTS關(guān)聯(lián)映射多對多一對多一對一66<resultMap>元素自動映射級別14325關(guān)聯(lián)映射01第4章MyBatis的關(guān)聯(lián)映射為什么學(xué)習(xí)MyBatis關(guān)聯(lián)關(guān)系?關(guān)聯(lián)關(guān)系概述68
實際的開發(fā)中,對數(shù)據(jù)庫的操作常常會涉及到多張表,這在面向?qū)ο笾芯蜕婕暗搅藢ο笈c對象之間的關(guān)聯(lián)關(guān)系。針對多表之間的操作,MyBatis提供了關(guān)聯(lián)映射,通過關(guān)聯(lián)映射就可以很好的處理對象與對象之間的關(guān)聯(lián)關(guān)系。本章中,將對MyBatis的關(guān)聯(lián)關(guān)系映射進(jìn)行詳細(xì)的講解。STEP01
在關(guān)系型數(shù)據(jù)庫中,表與表之間存在著三種關(guān)聯(lián)映射關(guān)系,分別為一對一關(guān)系、一對多關(guān)系和多對多關(guān)系。STEP03關(guān)聯(lián)映射關(guān)系關(guān)聯(lián)映射的概述69一對一一個數(shù)據(jù)表中的一條記錄最多可以和另一個數(shù)據(jù)表中的一條記錄相關(guān)。例如,現(xiàn)實生活中學(xué)生與校園卡就屬于一對一的關(guān)系,一個學(xué)生只能擁有一張校園卡,一張校園卡只能屬于一個學(xué)生。一對多主鍵數(shù)據(jù)表中的一條記錄可以和另外一個數(shù)據(jù)表的多條記錄相關(guān)。但另外一個數(shù)據(jù)表中的記錄只能與主鍵數(shù)據(jù)表中的某一條記錄相關(guān)。例如,現(xiàn)實中班級與學(xué)生的關(guān)系就屬于一對多的關(guān)系,一個班級可以有很多學(xué)生,但一個學(xué)生只能屬于一個班級。多對多一個數(shù)據(jù)表中的一條記錄可以與另外一個數(shù)據(jù)表任意數(shù)量的記錄相關(guān),另外一個數(shù)據(jù)表中的一條記錄也可以與本數(shù)據(jù)表中任意數(shù)量的記錄相關(guān)。例如,現(xiàn)實中學(xué)生與教師屬于多對多的關(guān)系,一名學(xué)生可以由多名教師授課,一名教師可以為多名學(xué)生授課。關(guān)聯(lián)關(guān)系概述70
在關(guān)系型數(shù)據(jù)庫中,多表之間存在著三種關(guān)聯(lián)關(guān)系,分別為一對一、一對多和多對多,如下圖所示:一對一一對多多對多在任意一方引入對方主鍵作為外鍵;在“多”的一方,添加“一”的一方的主鍵作為外鍵;產(chǎn)生中間關(guān)系表,引入兩張表的主鍵作為外鍵,兩個主鍵成為聯(lián)合主鍵或使用新的字段作為主鍵。關(guān)聯(lián)關(guān)系概述71
在Java中,通過對象也可以進(jìn)行關(guān)聯(lián)關(guān)系描述,如圖所示:一對一一對多多對多在本類中定義對方類型的對象,如A類中定義B類類型的屬性b,B類中定義A類類型的屬性a;一個A類類型對應(yīng)多個B類類型的情況,需要在A類中以集合的方式引入B類類型的對象,在B類中定義A類類型的屬性a;在A類中定義B類類型的集合,在B類中定義A類類型的集合。一對一02第4章MyBatis的關(guān)聯(lián)映射一對一73
在現(xiàn)實生活中,一對一關(guān)聯(lián)關(guān)系是十分常見的。例如,一個人只能有一個身份證,同時一個身份證也只會對應(yīng)一個人。
那么使用MyBatis是怎么處理圖中的這種一對一關(guān)聯(lián)關(guān)系的呢?
在前面章節(jié)所講解的<resultMap>元素中,包含了一個<association>子元素,MyBatis就是通過該元素來處理一對一關(guān)聯(lián)關(guān)系的。一對一74
在<association>元素中,通??梢耘渲靡韵聦傩?property指定映射到的實體類對象屬性,與表字段一一對應(yīng)columnjavaType指定映射到實體對象屬性的類型指定表中對應(yīng)的字段select指定引入嵌套查詢的子SQL語句,該屬性用于關(guān)聯(lián)映射中的嵌套查詢fetchType指定在關(guān)聯(lián)查詢時是否啟用延遲加載。該屬性有l(wèi)azy和eager兩個屬性值,默認(rèn)值為lazy(即默認(rèn)關(guān)聯(lián)映射延遲加載)一對一75MyBatis加載關(guān)聯(lián)關(guān)系對象主要通過兩種方式:嵌套查詢和嵌套結(jié)果。
嵌套查詢是通過執(zhí)行另外一條SQL映射語句來返回預(yù)期的復(fù)雜類型。
嵌套結(jié)果是使用嵌套結(jié)果映射來處理重復(fù)的聯(lián)合結(jié)果的子集。第一種第二種嵌套查詢是在查詢SQL中嵌入一個子查詢SQL;嵌套結(jié)果是一個嵌套的多表查詢SQL;嵌套查詢會執(zhí)行多條SQL語句;嵌套結(jié)果只會執(zhí)行一條復(fù)雜的SQL語句;嵌套查詢SQL語句編寫較為簡單;嵌套結(jié)果SQL語句編寫比較復(fù)雜;一對一76
雖然使用嵌套查詢的方式比較簡單,但是嵌套查詢的方式要執(zhí)行多條SQL語句,這對于大型數(shù)據(jù)集合和列表展示不是很好,因為這樣可能會導(dǎo)致成百上千條關(guān)聯(lián)的SQL語句被執(zhí)行,從而極大的消耗數(shù)據(jù)庫性能并且會降低查詢效率。那怎么解決這種問題呢?一對一77
使用MyBatis的延遲加載在一定程度上可以降低運行消耗并提高查詢效率。MyBatis默認(rèn)沒有開啟延遲加載,需要在核心配置文件中的<settings>元素內(nèi)進(jìn)行配置,具體配置方式如下:多學(xué)一招:MyBatis延遲加載的配置<settings><settingname="lazyLoadingEnabled"value="true"/><settingname="aggressiveLazyLoading"value="false"/></settings>
在映射文件中,<association>元素和<collection>元素中都已默認(rèn)配置了延遲加載屬性,即默認(rèn)屬性fetchType="lazy"(屬性fetchType="eager"表示立即加載),所以在配置文件中開啟延遲加載后,無需在映射文件中再做配置。一對一78
使用<association>元素進(jìn)行一對一關(guān)聯(lián)映射非常簡單,只需要參考如下兩種示例配置即可。<resultMaptype="IdCard"id="IdCardById"> <idproperty="id"column="id"/> <resultproperty="userName"column="userName"/> <!--一對一:association使用select屬性引入另外一條SQL語句--> <associationproperty="user"column="uid"javaType="User"
select="cn.dsscm.dao.UserMapper.findUserById"/></resultMap>算術(shù)運算符邏輯運算符<resultMaptype="IdCard"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="code"column="code"/> <associationproperty="user"javaType="User"> <idproperty="id"column="cid"/> <resultproperty="userName"column="userName"/> </association></resultMap>嵌套的子查詢類屬性類屬性表字段表字段關(guān)聯(lián)屬性類型方法2:嵌套結(jié)果方法1:嵌套查詢resultMap79resultMap屬性id:resultMap的唯一標(biāo)識type:Java實體類resultMap子元素id一般對應(yīng)數(shù)據(jù)庫中該行的主鍵id,設(shè)置此項可提高M(jìn)yBatis性能result映射到JavaBean的某個“簡單類型”屬性association映射到JavaBean的某個“復(fù)雜類型”屬性,比如JavaBean類collection映射到JavaBean的某個“復(fù)雜類型”屬性,比如集合resultMap80association復(fù)雜的類型關(guān)聯(lián),一對一內(nèi)部嵌套映射一個嵌套JavaBean屬性屬性property:映射數(shù)據(jù)庫列的實體對象的屬性javaType:完整Java類名或者別名resultMap:引用外部resultMap子元素idresultproperty:映射數(shù)據(jù)庫列的實體對象的屬性column:數(shù)據(jù)庫列名或者別名用戶和身份證間關(guān)聯(lián)-1嵌套查詢
<!--嵌套查詢:通過執(zhí)行另外一條SQL映射語句來返回預(yù)期的特殊類型--><selectid="findCodeById"parameterType="Integer"resultMap="IdCardById"> SELECT*FROMtb_idcardWHEREid=#{id}</select><resultMaptype="IdCard"id="IdCardById"> <idproperty="id"column="id"/> <resultproperty="userName"column="userName"/> <!--一對一:association使用select屬性引入另外一條SQL語句--> <associationproperty="user"column="uid"javaType="User"
select="cn.dsscm.dao.UserMapper.findUserById"/></resultMap><!--根據(jù)id查詢用戶信息--><selectid="findUserById"parameterType="Integer"resultType="User"> SELECT*fromtb_userwhereid=#{id}</select>81用戶和身份證間關(guān)聯(lián)-2嵌套結(jié)果<!--根據(jù)roleId獲取用戶列表associationstart--><resultMaptype="IdCard"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="code"column="code"/> <associationproperty="user"javaType="User"> <idproperty="id"column="cid"/> <resultproperty="userName"column="userName"/> </association></resultMap><selectid="findCodeById2"parameterType="Integer"resultMap="userRoleResult2"> SELECTu.*,c.idcid,c.code FROMtb_useru,tb_idcardc WHEREu.id=c.uid ANDc.uid=#{uid}</select>82用戶和用戶角色關(guān)聯(lián)-183嵌套結(jié)果<!--根據(jù)roleId獲取用戶列表associationstart--><resultMaptype="User"id="userRoleResult"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/>
<associationproperty="role"javaType="Role"> <idproperty="id"column="r_id"/> <resultproperty="roleCode"column="roleCode"/> <resultproperty="roleName"column="roleName"/> </association></resultMap><selectid="getUserListByRoleId"parameterType="Integer"resultMap="userRoleResult"> selectu.*,r.idasr_id,r.roleCode,r.roleName fromtb_useru,tb_roler whereu.userRole=#{userRole}andu.userRole=r.id</select>用戶和用戶角色關(guān)聯(lián)-284嵌套結(jié)果resultMap實現(xiàn)association的結(jié)果映射<!--根據(jù)roleId獲取用戶列表associationstart--><resultMaptype="User"id="userRoleResult2"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/> <associationproperty="role"javaType="Role"resultMap="roleResult"/></resultMap><resultMaptype="Role"id="roleResult"> <idproperty="id"column="r_id"/> <resultproperty="roleCode"column="roleCode"/> <resultproperty="roleName"column="roleName"/></resultMap><selectid="getUserListByRoleId2"parameterType="Integer"resultMap="userRoleResult2"> selectu.*,r.idasr_id,r.roleCode,r.roleNamefromtb_useru,tb_roler whereu.userRole=#{userRole}andu.userRole=r.id</select>實現(xiàn)訂單表的查詢(association)85需求說明:實現(xiàn)按條件查詢訂單表,查詢條件如下:商品名稱(模糊查詢)供應(yīng)商(供應(yīng)商id)是否付款查詢結(jié)果列顯示:訂單編碼、商品名稱、供應(yīng)商編碼、供應(yīng)商名稱、供應(yīng)商聯(lián)系人、供應(yīng)商聯(lián)系電話、訂單金額、是否付款resultMap中使用association子元素完成內(nèi)部嵌套修改Bill.java,增加復(fù)雜類型屬性:Provider編寫SQL查詢語句(連表查詢)創(chuàng)建resultMap-自定義映射結(jié)果,并在select中引用完成時間:20分鐘練習(xí)指導(dǎo)共性問題集中講解86常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解一對多03第4章MyBatis的關(guān)聯(lián)映射一對多88
開發(fā)人員接觸更多的關(guān)聯(lián)關(guān)系是一對多(或多對一)。例如,一個用戶可以有多個訂單,同時多個訂單歸一個用戶所有。
那么使用MyBatis是怎么處理這種一對多關(guān)聯(lián)關(guān)系的呢?
在前面章節(jié)所講解的<resultMap>元素中,包含了一個<collection>子元素,MyBatis就是通過該元素來處理一對多關(guān)聯(lián)關(guān)系的。一對多89ofTypeofType屬性與javaType屬性對應(yīng),它用于指定實體對象中集合類屬性所包含的元素類型。
<collection>子元素的屬性大部分與<association>元素相同,但其還包含一個特殊屬性--ofType。一對多90<collection>元素的使用也非常簡單,同樣可以參考如下兩種示例進(jìn)行配置,具體代碼如下:方法1:嵌套查詢<collectionproperty="users"column="id"ofType="User"select="cn.dsscm.dao.selectUsers"/>方法2:嵌套結(jié)果<collectionproperty="users"ofType="User"> <idproperty="id"column="id"/> <resultproperty="userCode"column="userCode"/> <resultproperty="userName"column="userName"/> <resultproperty="userRole"column="userRole"/></collection>嵌套的子查詢類屬性類屬性表字段表字段關(guān)聯(lián)的集合類屬性類型resultMap91collection復(fù)雜類型集合,一對多內(nèi)部嵌套映射一個嵌套結(jié)果集到一個列表屬性property:映射數(shù)據(jù)庫列的實體對象的屬性ofType:完整Java類名或者別名(集合所包括的類型)resultMap:引用外部resultMap子元素idresultproperty:映射數(shù)據(jù)庫列的實體對象的屬性column:數(shù)據(jù)庫列名或者別名用戶角色關(guān)聯(lián)用戶信息92嵌套結(jié)果<resultMaptype="Role"id="rolelist"><idproperty="id"column="rid"/><resultproperty="roleName"column="roleName"/><collectionproperty="users"ofType="User"><idproperty="id"column="id"/><resultproperty="userCode"column="userCode"/><resultproperty="userName"column="userName"/><resultproperty="userRole"column="userRole"/></collection></resultMap><selectid="getRole"resultMap="rolelist"> SELECTr.idrid,r.roleName,r.roleCode,u.* FROMtb_roler,tb_useru WHEREr.id=u.userRole <iftest="id>0">ANDr.id=#{id}</if></select>publicclassRole{ ……
privateList<User>users;}商品類型關(guān)聯(lián)商品信息93嵌套結(jié)果<resultMaptype="ProductCategory"id="productlist"><idproperty="id"column="cid"/><resultproperty="name"column="cname"/><collectionproperty="products"ofType="Product"><idproperty="id"column="id"/><resultproperty="name"column="name"/><resultproperty="price"column="price"/><resultproperty="stock"column="stock"/></collection></resultMap><selectid="getProduct"resultMap="productlist"> SELECTc.idcid,cname,p.* FROMtb_product_categoryc,tb_productp WHEREc.id=p.categoryLevel1Id <iftest="id>0">ANDc.id=#{id}</if> ORDERBYc.id</select>publicclassProductCategoryimplementsSerializable{ ……
privateList<Product>products; //省略getter和setter方法}resultMap94如何提高結(jié)果映射的可重用性?collection的resultMap屬性分析問題獲取供應(yīng)商及其訂單列表(collection)95需求說明:根據(jù)指定的供應(yīng)商(id)查詢出其相關(guān)信息以及其下所有的訂單列表查詢結(jié)果列顯示:供應(yīng)商id、供應(yīng)商編碼、供應(yīng)商名稱、供應(yīng)商聯(lián)系人、供應(yīng)商聯(lián)系電話、訂單列表信息(訂單編碼、商品名稱、訂單金額、是否付款)resultMap中使用collection子元素完成內(nèi)部嵌套修改Provider.java,增加集合類型屬性:List<Bill>billList編寫SQL查詢語句(連表查詢)創(chuàng)建resultMap-自定義映射結(jié)果,并在select中引用完成時間:20分鐘練習(xí)指導(dǎo)共性問題集中講解96常見問題及解決辦法代碼規(guī)范問題調(diào)試技巧共性問題集中講解多對多04第4章MyBatis的關(guān)聯(lián)映射多對多98
在實際項目開發(fā)中,多對多的關(guān)聯(lián)關(guān)系也是非常常見的。以訂單和商品為例,一個訂單可以包含多種商品,而一種商品又可以屬于多個訂單。
在數(shù)據(jù)庫中,多對多的關(guān)聯(lián)關(guān)系通常使用一個中間表來維護(hù),中間表中的訂單id作為外鍵參照訂單表的id,商品id作為外鍵參照商品表的id。銷售訂單關(guān)聯(lián)訂購商品信息-199嵌套查詢
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《網(wǎng)絡(luò)b安全b》課件
- 第3單元 中國特色社會主義道路(A卷·知識通關(guān)練)(解析版)
- 2014年高考語文試卷(新課標(biāo)Ⅱ卷)(解析卷)
- 中國非遺文化魚燈介紹2
- 羽絨服的成本控制與優(yōu)化設(shè)計-洞察分析
- 雨水收集設(shè)施維護(hù)與監(jiān)測-洞察分析
- 體育游戲在體育教育中的應(yīng)用-洞察分析
- 香菇多糖生物活性分析-洞察分析
- 舞蹈康復(fù)對精神疾病患者心理創(chuàng)傷的治愈-洞察分析
- 網(wǎng)絡(luò)流量監(jiān)測技術(shù)-洞察分析
- Unit13 同步教學(xué)設(shè)計2023-2024學(xué)年人教版九年級英語全冊
- 2023-2024學(xué)年河北省保定市滿城區(qū)八年級(上)期末英語試卷
- 2024成都中考數(shù)學(xué)第一輪專題復(fù)習(xí)之專題四 幾何動態(tài)探究題 教學(xué)課件
- 2024合同范本之太平洋保險合同條款
- 萬用表的使用
- TDT1062-2021《社區(qū)生活圈規(guī)劃技術(shù)指南》
- GB/T 12959-2024水泥水化熱測定方法
- 《商務(wù)禮儀》試題及答案大全
- 《核電廠焊接材料評定與驗收標(biāo)準(zhǔn)》
- MOOC 數(shù)字邏輯電路實驗-東南大學(xué) 中國大學(xué)慕課答案
- 小學(xué)生建筑科普小知識
評論
0/150
提交評論