ORM框架之Mybatis(四):映射文件resultMap標(biāo)簽詳解

Mybatis的映射文件中頂級的標(biāo)簽并不多方咆,之前有說過select月腋、updatedelete瓣赂、insert榆骚、sql等標(biāo)簽,resultMap在之前的文章也有提過煌集,但是當(dāng)時也是簡單的提過妓肢,其實(shí)這個標(biāo)簽里面的內(nèi)容很多,可簡單可復(fù)雜苫纤。正常開發(fā)中簡單的基本都在使用碉钠,但是涉及到復(fù)雜的用的就少啦。

association實(shí)現(xiàn)一對一的查詢卷拘,collection實(shí)現(xiàn)一對多的查詢喊废,discriminator實(shí)現(xiàn)鑒別器的功能,也就是根據(jù)不同的條件實(shí)現(xiàn)不同的關(guān)聯(lián)查詢栗弟。為什么說用到這些復(fù)雜的內(nèi)容很少呢污筷。以前在項(xiàng)目上性能要求不是很高,對分庫分表概念沒有那么高的時候乍赫,采用關(guān)聯(lián)查詢其實(shí)沒有什么不好瓣蛀,但是現(xiàn)在互聯(lián)網(wǎng)發(fā)展迅速,數(shù)據(jù)量變得龐大雷厂,查詢SQL的性能要求也變得更高惋增。關(guān)聯(lián)查詢在大數(shù)據(jù)量的時候執(zhí)行效率不高也就格外的凸顯出來了。如果看過阿里的Java開發(fā)手冊可以知道罗侯,他們是不推薦關(guān)聯(lián)查詢器腋,而是提倡單表操作,如果需要查其他表信息,就根據(jù)條件纫塌,操作其他單表诊县。

雖然關(guān)聯(lián)查詢操作變少,但是面試的時候還是可以用來問的措左。不管從哪一個方面來說擴(kuò)展知識面都不是壞事依痊。

resultMap子標(biāo)簽之a(chǎn)ssociation標(biāo)簽

在說association標(biāo)簽的具體使用前,先說一下兩種關(guān)聯(lián)查詢方式怎披。

  • 嵌套結(jié)果:使用嵌套結(jié)果映射來處理重復(fù)的聯(lián)合結(jié)果的子集
  • 嵌套查詢:通過執(zhí)行另外一個 SQL 映射語句來返回預(yù)期的復(fù)雜類型

咋一看上面的兩個概念很難理解胸嘁,下面用代碼體現(xiàn)一下。

嵌套結(jié)果方式
//用戶類
public class User{
    private Integer id;
    private String user_name;
    private String phone;
    private String email;
    private Father father;
}
//父親類
public class Father{
    private Integer id;
    private String name;
    private Integer age;
}
<!--用戶表基礎(chǔ)字段的映射關(guān)系-->
<resultMap id="userBaseColumnMap" type="com.zdydoit.core.model.User">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="phone" column="phone"/>
    <result property="email" column="email"/>
</resultMap>
<!-- 嵌套結(jié)果方式 -->
<resultMap id="selectUserMap1" extends="userBaseColumnMap" type="com.zdydoit.core.model.User">
    <association property="father" javaType="com.zdydoit.core.model.Father" columnPrefix="tf_">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
    </association>
</resultMap>
<!--查詢語句-->
<select id="slectUser1" resultMap="selectUserMap1" parameterType="java.lang.Integer">
    select
    tu.id,
    tu.user_name,
    tu.phone,
    tu.email,
    tu.father_id,
    tf.id tf_id,
    tf.name tf_name,
    tf.age tf_age
    from t_user tu,t_father tf
    where tu.id = #{id} and tu.father_id = tf.id
</select>

用戶表中有一個字段father凉逛,對應(yīng)的是Father實(shí)體類性宏,每人都有一個父親,而且是一對一的關(guān)系状飞,至于那些大干爹毫胜、二干爹這里不做考慮。查詢出來的結(jié)果用戶信息的字段自然封裝到User中诬辈,那父親的信息就是放在father字段中酵使。

查詢語句對應(yīng)的resultMapselectUserMap1selectUserMap1是繼承userBaseColumnMap焙糟,這里繼承可以理解成java里面的繼承口渔,也就是說繼承了父類的字段映射關(guān)系。重點(diǎn)看的是association標(biāo)簽穿撮,property屬性對應(yīng)的是User類中的father字段缺脉,表示association內(nèi)的查詢結(jié)果是封裝在father字段中,對應(yīng)的javaType自然就是Father悦穿,columnPrefix表示字段的前綴枪向,這里加上前綴是很有必要的,因?yàn)樵趦蓚€表做關(guān)聯(lián)的時候咧党,可能會存在數(shù)據(jù)庫中字段名相同,那么在這里如果不用別名陨亡,就會導(dǎo)致兩個字段映射過程混亂傍衡。

嵌套查詢方式

這種方式需要關(guān)聯(lián)到另一個命名空間,上面的例子是在同一個命名空間com.zdydoit.core.mapper.UserMapper下负蠕。這里的另一個命名空間就是com.zdydoit.core.mapper.FatherMapper蛙埂。

實(shí)體類的代碼和上面的一樣,下面只做映射關(guān)系的展示遮糖。

com.zdydoit.core.mapper.UserMapper命名空間下:

<!-- 嵌套查詢方式 -->
<resultMap id="selectUserMap2" type="com.zdydoit.core.model.User">
    <association property="father" column="father_id" select="com.zdydoit.core.mapper.FatherMapper.selectById"/>
</resultMap>
<!-- 查詢語句 -->
<select id="selectUser2" resultMap="selectUserMap2" parameterType="java.lang.Integer">
    select
    id,
    user_name,
    phone,
    email,
    father_id
    from t_user
    where id = #{id}
</select>

com.zdydoit.core.mapper.FatherMapper命名空間下:

<resultMap id="fatherBaseColumnMap" type="com.zdydoit.core.model.Father">
    <id property="id" column="id"/>
    <result property="name" column="name" />
    <result property="age" column="age" />
</resultMap>
<!-- 單表查詢 -->
<select id="selectById" resultMap="fatherBaseColumnMap">
    select
    id,
    name,
    age
    from t_father
    where id = #{father_id}
</select>

這樣查詢的過程稍微有點(diǎn)繞绣的。首先是對t_user表執(zhí)行單表查詢操作,查詢的結(jié)果中有一個字段father_id,然后就是association標(biāo)簽將這個字段作為條件傳給com.zdydoit.core.mapper.FatherMapper命名空間屡江,執(zhí)行另一個單表查詢操作selectById查詢Father的信息芭概。和之前的區(qū)別就是,之前是一個SQL執(zhí)行關(guān)聯(lián)查詢惩嘉,現(xiàn)在是用多個單表查詢組合得到查詢結(jié)果罢洲。

這里只有一個查詢條件father_id,如果有多個寫法就按下面的寫法文黎。

<!-- 
這里旨在說明column多參數(shù)的寫法
'rel_'開頭的值表示SQL語句里面查詢出的字段名
等號左邊的表示在selectInfo中引用的字段名稱 
-->
<association property = "father" colum="{id = rel_id,age = rel_age,nickname = rel_nickname}" select="com.zdydoit.mapper.XxxMapper.selectInfo">

association標(biāo)簽的屬性很多惹苗,下面總結(jié)一下常用標(biāo)簽的含義。

  • property屬性耸峭,這個屬性是必須的桩蓉,對應(yīng)的是實(shí)體類中的字段,和result標(biāo)簽的property屬性是相同含義的劳闹。
  • resultMap屬性院究,association標(biāo)簽內(nèi)也有idreuslt標(biāo)簽玷或,用來做關(guān)聯(lián)類的字段映射關(guān)系儡首,當(dāng)然這個關(guān)系也可以通過一個reusltMap表示,省去association內(nèi)寫過多的映射關(guān)系偏友。這種reusltMap指定可以跨命名空間蔬胯。
  • column屬性,在嵌套查詢方式的時候使用位他,用來給嵌套語句查詢傳遞條件氛濒,可以傳遞多個。
  • columnPrefix屬性鹅髓,在嵌套結(jié)果方式的時候使用舞竿,用來指定別名字段的前綴,可用于防止兩個表結(jié)果字段重名問題窿冯。
  • select屬性骗奖,在嵌套查詢方式的時候使用,用來指定嵌套語句查詢的具體坐標(biāo)醒串。
  • fetchType屬性执桌,這個屬性有兩個可選值,分別是lazyeager,分別表示是否懶加載芜赌,如果設(shè)置為懶加載仰挣,在主類中沒有使用到這個關(guān)聯(lián)對象,就會少一次關(guān)聯(lián)字句查詢的過程缠沈,只有使用的時候才去查詢膘壶。
  • javaType屬性错蝴,指定關(guān)聯(lián)對象的具體類型。

resultMap子標(biāo)簽之collection標(biāo)簽

collectionassociation標(biāo)簽的使用方式是相同的颓芭,也包含兩種關(guān)聯(lián)查詢方式顷锰,唯一不同的就是association只能對應(yīng)一條記錄,是一對一的關(guān)系畜伐,使用單個類字段來接收馍惹,collection可以對應(yīng)多條記錄,是一對多的關(guān)系玛界,接收使用集合方式万矾。

還有就是collection多了一個ofType字段,這個字段是用來指定集合內(nèi)元素的類型慎框,如下:

private List<Computer> computers;

這個是有ofType對應(yīng)的類型就是Computer良狈。同樣理解javaType對應(yīng)的類型就是List。不過這里一般都不會手動去指定javaType笨枯,會自動映射到集合中薪丁。

resultMap子標(biāo)簽之discriminator標(biāo)簽

這個應(yīng)用場景感覺不多,不過還是可以舉個栗子理解一下的馅精。

在做體檢的時候严嗜,男性和女性體檢內(nèi)容是有區(qū)別的。現(xiàn)在有三張表洲敢,分別是人員表漫玄、男性體檢報告表、女性體檢報告表压彭。要求查一個人的體檢報告睦优。那很簡單是當(dāng)這個人是男性的時候,查詢其體檢報告是從男性體檢報告表中查詢壮不,反之就到女性體檢報告表中查詢汗盘。實(shí)現(xiàn)方式如下:

<!-- 人員基礎(chǔ)信息 -->
<resultMap id="personBaseColumnMap" type="Person">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="gender" column="gender"/>
</resultMap>

<!-- 查詢女性體檢報告 -->
<resultMap id="healthReportFemaleMap" extends="personReportMap" type="Person">
    <collection property="healthReports" column="id" select="com.zdydoit.mapper.HealthFemaleMapper.selectByPersonId"/>
</resultMap>

<!-- 查詢男性體檢報告 -->
<resultMap id="healthReportMaleMap" extends="personReportMap" type="Person">
    <collection property="healthReports" column="id" select="com.zdydoit.mapper.HealthMaleMapper.selectByPersonId"/>
</resultMap>

<!-- 查詢?nèi)藛T信息+體檢報告 -->
<resultMap id="personReportMap" extends="personBaseColumnMap" type="Person">
    <discriminator javaType="java.lang.Integer" column="gender">
        <case value="1" resultMap="healthReportMaleMap"/>
        <case value="2" resultMap="healthReportFemaleMap"/>
    </discriminator>
</resultMap>

<!-- 查詢語句 -->
<select id="selectPersonReport" resultMap="personReportMap" parameterType="java.lang.Integer">
    select id,name,gender from t_person where id = #{id}
</select>
    

有幾點(diǎn)需要說一下。

  • case標(biāo)簽里面結(jié)果涉及到兩個報告類型分別是HealthReportMaleHealthReportFemale询一,但是Person類中可以定義兩個字段分別接收這兩種隐孽,也可以用一個字段接收,這個接收字段集合的元素類型應(yīng)該定義一個父類HealthReport健蕊,讓HealthReportMaleHealthReportFemale都繼承這個父類缓醋。
  • case標(biāo)簽內(nèi)有resultTyperesultMap兩種指定結(jié)果的方式,這里使用的都是resultMap的方式绊诲,因?yàn)檫@種方式更優(yōu)。如果使用resultType褪贵,只能使用嵌套結(jié)果方式掂之,然后又涉及到多張不同的表抗俄,代碼量變大,而且是重復(fù)的代碼量世舰。這里稍微有點(diǎn)難理解动雹,可以上手寫一下就知道了。
  • resultMap的繼承關(guān)系跟压,這里涉及到多個resultMap胰蝠,select標(biāo)簽指定的是personReportMap,是直接resultMap震蒋,personReportMap繼承personBaseColumnMap茸塞,因?yàn)槿藛T基礎(chǔ)信息映射關(guān)系都在這個personBaseColumnMap中,然后case內(nèi)的healtReportMaleMaphealthReportFemaleMap都是繼承personReportMap

Overview

習(xí)慣性的總結(jié)一下查剖。

  • 說了兩種關(guān)聯(lián)查詢方式钾虐,分別是嵌套結(jié)果和嵌套查詢,貫穿了三個標(biāo)簽的使用笋庄。
  • association標(biāo)簽用于一對一的關(guān)聯(lián)查詢效扫,主要屬性也做了說明。
  • collection標(biāo)簽用于一對多的關(guān)聯(lián)查詢直砂,沒有具體說菌仁,可以參考association標(biāo)簽的解釋,基本相同静暂。
  • discriminator標(biāo)簽济丘,使用的過程最為復(fù)雜,主要的是要理清resultMap的繼承關(guān)系籍嘹。
  • 這些標(biāo)簽在實(shí)際開發(fā)中很少用到闪盔,現(xiàn)在都提倡單表操作,簡單高效辱士,兼容分庫分表等泪掀。因此只做了解,掃知識盲點(diǎn)颂碘,提高面試底氣异赫。但是resultMap標(biāo)簽的基本使用是簡單的,而且是極其重要的头岔。

resultMap標(biāo)簽是很重要的塔拳,甚至可以說是極其的重要,但是這些關(guān)聯(lián)查詢的功能標(biāo)簽不是很重要峡竣,這個是不相悖的靠抑。

resultMap有個很大的優(yōu)點(diǎn)就是解耦合(阿里Java手冊也著重強(qiáng)調(diào))。如果使用自動映射的話适掰,會將數(shù)據(jù)庫列表和實(shí)體類的字段名強(qiáng)耦合颂碧,當(dāng)數(shù)據(jù)庫列表發(fā)生修改時荠列,實(shí)體類中的字段名也要同步修改。但是使用resultMap指定映射關(guān)系载城,當(dāng)有數(shù)據(jù)庫列名發(fā)生變化肌似,只要改一下映射中的column值即可,實(shí)體類無需任何修改變動诉瓦。

本文作者:程序猿楊鮑
版權(quán)歸作者所有川队,轉(zhuǎn)載請注明出處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睬澡,隨后出現(xiàn)的幾起案子固额,更是在濱河造成了極大的恐慌,老刑警劉巖猴贰,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件对雪,死亡現(xiàn)場離奇詭異,居然都是意外死亡米绕,警方通過查閱死者的電腦和手機(jī)瑟捣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅干,“玉大人迈套,你說我怎么就攤上這事〖盍郏” “怎么了桑李?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窿给。 經(jīng)常有香客問我贵白,道長,這世上最難降的妖魔是什么崩泡? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任禁荒,我火速辦了婚禮,結(jié)果婚禮上角撞,老公的妹妹穿的比我還像新娘呛伴。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凝果,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姐军。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音奕锌,去河邊找鬼衫贬。 笑死,一個胖子當(dāng)著我的面吹牛歇攻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梆造,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼缴守,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了镇辉?” 一聲冷哼從身側(cè)響起屡穗,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忽肛,沒想到半個月后村砂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屹逛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年础废,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罕模。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡评腺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淑掌,到底是詐尸還是另有隱情蒿讥,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布抛腕,位于F島的核電站芋绸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏担敌。R本人自食惡果不足惜摔敛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柄错。 院中可真熱鬧舷夺,春花似錦、人聲如沸售貌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颂跨。三九已至敢伸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恒削,已是汗流浹背池颈。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工尾序, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躯砰。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓每币,卻偏偏與公主長得像,于是被迫代替她去往敵國和親琢歇。 傳聞我的和親對象是個殘疾皇子兰怠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL李茫、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,429評論 0 4
  • title: MyBatis之使用resultMap實(shí)現(xiàn)高級映射tags: MyBatiscategories: ...
    codingXiaxw閱讀 1,524評論 1 1
  • MyBatis 理論篇 [TOC] 什么是MyBatis ?MyBatis是支持普通SQL查詢,存儲過程和高級映射...
    有_味閱讀 2,883評論 0 26
  • SQL 映射文件的頂級元素(按照它們應(yīng)該被定義的順序): cache – 給定命名空間的緩存配置揭保。 cache-r...
    悠揚(yáng)前奏閱讀 694評論 0 0
  • 周末上班,帶著大寶貝值班魄宏,我想讓他在我單位安安靜靜的做作業(yè)秸侣,抽空中午帶孩子出去玩一趟,這兩天和寶貝關(guān)系不是很好宠互,我...
    愛你的貝貝閱讀 315評論 3 8