Mybatis的映射文件中頂級的標(biāo)簽并不多方咆,之前有說過select
月腋、update
、delete
瓣赂、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)的resultMap
是selectUserMap1
,selectUserMap1
是繼承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)也有id
、reuslt
標(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
屬性执桌,這個屬性有兩個可選值,分別是lazy
和eager
,分別表示是否懶加載芜赌,如果設(shè)置為懶加載仰挣,在主類中沒有使用到這個關(guān)聯(lián)對象,就會少一次關(guān)聯(lián)字句查詢的過程缠沈,只有使用的時候才去查詢膘壶。 -
javaType
屬性错蝴,指定關(guān)聯(lián)對象的具體類型。
resultMap子標(biāo)簽之collection標(biāo)簽
collection
和association
標(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é)果涉及到兩個報告類型分別是HealthReportMale
和HealthReportFemale
询一,但是Person
類中可以定義兩個字段分別接收這兩種隐孽,也可以用一個字段接收,這個接收字段集合的元素類型應(yīng)該定義一個父類HealthReport
健蕊,讓HealthReportMale
和HealthReportFemale
都繼承這個父類缓醋。 -
case
標(biāo)簽內(nèi)有resultType
和resultMap
兩種指定結(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)的healtReportMaleMap
和healthReportFemaleMap
都是繼承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)載請注明出處