簡(jiǎn)單查詢-resulttype
數(shù)據(jù)準(zhǔn)備
字段 | 注釋 |
---|---|
sno | 學(xué)號(hào) |
sname | 學(xué)生名字 |
ssex | 性別 |
sbirithday | 生日 |
class | 班級(jí) |
1
2
3
4
5
6
7
8
9
|
<!--建表語句:--> create table test.student ( sno varchar( 3 ) not null , sname varchar( 4 ) not null , ssex varchar( 2 ) not null , sbirthday datetime null , class varchar( 5 ) null ) |
1
2
3
4
5
6
7
8
9
10
11
|
<!--bean 文件--> public class student { private string sno; private string sname; private string ssex; private date sbirthday; private string class ; <!--get 和 set 方法--> ... } |
例子
按照返回?cái)?shù)據(jù)類型大致分為基礎(chǔ)數(shù)據(jù)類型,javabean 和 map。其中雖然返回的結(jié)果行數(shù)有單條也有多條,對(duì)應(yīng)的接口返回類型是集合或者單個(gè)對(duì)象,但是在 xml 映射文件中,resulttype 的值是相同的。
1、指定字段-基礎(chǔ)數(shù)據(jù)類型
接口類:
1
2
3
4
|
mapper 文件:
1
2
3
4
5
6
7
8
|
<!--單條結(jié)果集--> <select id= "querysinglestudent" resulttype= "string" > select sname from test.student limit 1 </select> <!--多條結(jié)果集--> <select id= "queryallstudent" resulttype= "string" > select sname from test.student </select> |
2、map,一般為 hashmap
接口類:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<!--單條結(jié)果集--> map<string, object> querystudentmap(); <!--多條結(jié)果集--> list<map<string, object>> queryallstudentmap(); 復(fù)制代碼mapper 文件: <!--單條結(jié)果集--> <select id= "querystudentmap" resulttype= "hashmap" > select sname from test.student limit 1 </select> <!--多條結(jié)果集--> <select id= "queryallstudentmap" resulttype= "hashmap" > select sname from test.student </select> |
其中:
- hashmap 為簡(jiǎn)寫,也可以使用 java.util.hashmap 全稱
-
默認(rèn)情況下,結(jié)果集中值為 null 時(shí), 不會(huì)增加映射對(duì)象的 setter 方法, (map 對(duì)象時(shí)為 put)。該行為可以在 mybatis-config.xml 配置文件中設(shè)置
<setting name="callsettersonnulls" value="true"/> 覆蓋默認(rèn)設(shè)定。
3、javabean
接口類:
1
2
3
4
|
<!--單條結(jié)果集--> student querysinglestudentbean(); <!--多條結(jié)果集--> list<student> queryallstudentbean(); |
mapper 文件:
1
2
3
4
5
6
7
8
|
<!--單條結(jié)果集--> <select id= "querystudentmap" resulttype= "student" > select sname from test.student limit 1 </select> <!--多條結(jié)果集--> <select id= "queryallstudentmap" resulttype= "student" > select sname from test.student </select> |
resulttype="student" 為 student.java 的別名,也可以是全限定名。別名在 mybatis-config.xml 配置文件中設(shè)置:
1
2
3
4
|
<typealiases> <typealias type= "com.bean.student" alias= "student" /> ... </typealiases> |
但是如果 javabean 文件很多,不想一個(gè)個(gè)指定,也可以使用 package 標(biāo)簽 設(shè)置mybatis自動(dòng)掃描,別名即為類名的小寫。
1
2
3
|
<typealiases> < package name= "包名" /> </typealiases> |
復(fù)雜查詢 resultmap
對(duì)于一般的查詢語句,resulttype 足夠了。對(duì)于多表查詢等情況,就要請(qǐng)出 resultmap 了。
數(shù)據(jù)庫(kù)字段和 java 數(shù)據(jù)類型映射關(guān)系
數(shù)據(jù)庫(kù)字段類型 jdbctype 和 java 數(shù)據(jù)類型 并不是一一對(duì)應(yīng)的關(guān)系,而且不同數(shù)據(jù)庫(kù)類型也不盡相同。而 mybatis 將 typehandler 作為兩者之間的映射關(guān)系。大部分情況下都是沒有問題的,但是并非能覆蓋所有的情況,特殊情況下可以使用 resultmap 自定義這種映射關(guān)系。
舉個(gè)例子,數(shù)據(jù)庫(kù) longvarchar 字段類型對(duì)應(yīng) java 中的 string 類型。但是在 db2 數(shù)據(jù)庫(kù)中,查詢的 longvarchar 類型的字段,在 mybatis 中被識(shí)別成 jdbctype 為 blob。有兩種解決方法,第一種是在 sql 中對(duì)該字段使用 cast 轉(zhuǎn)換為 varchar(長(zhǎng)度)類型。另一種是使用 resultmap:
1
2
3
4
5
6
7
|
<resultmap id= "resultmapdemo" type= "" automapping= "true" > <result property= "" column= "" jdbctype= "varchar" /> </resultmap> <select id= "demoid" resultmap= "resultmapdemo" > ... <select> |
1、<select>標(biāo)簽中使用 resultmap 指定返回集合。注意 resultmap 和 resulttype 不能同時(shí)使用
2、<resultmap> 標(biāo)簽
- id 和 select 標(biāo)簽指定映射關(guān)系
- type 和 resulttype 一樣為返回類型的全限定名或者別名
- automapping 自動(dòng)映射關(guān)系,在這里目的只是修改一個(gè)字段,其他自動(dòng)采用自動(dòng)完成映射關(guān)系
3、<result> 標(biāo)簽
- property 為 java 變量名
- column 為數(shù)據(jù)庫(kù)字段名
- jdbctype 這里指定為 varchar
id
字段的映射關(guān)系的標(biāo)簽即有,也有,在 mybatis 文檔中指出不使用id,會(huì)造成性能下降,因此將主鍵字段使用 id 標(biāo)簽是推薦的做法。但是如果不存在主鍵呢,當(dāng)你在 resultmap 只提供了部分字段而不是全部字段,即使使用了 automapping 屬性,那么 mybatis 會(huì)按照你提供的字段名進(jìn)行去重。那么在使用 resultmap 的時(shí)候,最優(yōu)選擇是:
- 如果表存在主鍵,就使用id標(biāo)簽指定
- 如果表不存在主鍵,要么不配置字段的映射關(guān)系,使用 automapping 屬性自動(dòng)映射;或者不使用 automapping 將所有字段羅列。
多表關(guān)聯(lián)查詢
在 resulttype 的例子中都只涉及到一張表,如果涉及多張表關(guān)聯(lián)查詢呢。我們可以簡(jiǎn)單的將所有列映射到 hashmap 的鍵值上。
但是 hashmap 不是一個(gè)很好的領(lǐng)域模型。 你的程序更可能會(huì)使用 javabean 或 pojo(plain old java objects,普通 java 對(duì)象)作為領(lǐng)域模型。
因此這里均采用 javabean 作為領(lǐng)域模型。增加一個(gè)成績(jī)表 score
字段 | 注釋 |
---|---|
sno | 學(xué)號(hào) |
cno | 課程編號(hào) |
degree | 成績(jī) |
1
2
3
4
5
6
7
|
<!--建表語句--> create table score ( sno varchar( 3 ) not null , cno varchar( 5 ) not null , degree decimal( 10 , 1 ) not null ) |
1
2
3
4
5
6
7
8
|
<!--bean 文件--> public class score { private string sno; private string cno; private double degree; <!--get 和 set 方法--> ... } |
一對(duì)一關(guān)系
這里的一對(duì)多關(guān)系是兩個(gè)表字段一一對(duì)應(yīng),一個(gè)學(xué)生的某門課的成績(jī)是唯一確定的。 在一一對(duì)應(yīng)的情況下要在 resultmap 中使用 標(biāo)簽。
在 student.java 中增加字段 score
1
2
3
4
5
6
7
8
|
<!--student.java--> private score score; public score getscore() { return score; } public void setscore(score score) { this .score = score; } |
有兩種使用情況,第一種為嵌套查詢,即前一個(gè) sql 查詢結(jié)果集中的字段作為參數(shù)傳遞給下一個(gè) sql。第二種情況為嵌套結(jié)果集,即兩個(gè)表做關(guān)聯(lián)查詢,將結(jié)果集映射到多個(gè) javabean 文件。
嵌套查詢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<resultmap id= "allstudentresultmap" type= "student" > <!--指定第二個(gè) select 語句,和傳遞的字段--> <association property= "score" column= "sno" select= "queryscore" /> </resultmap> <!--第一個(gè) sql --> <select id= "queryallstudent" resultmap= "allstudentresultmap" > select sno,sname from test.student </select> <!--第二個(gè) sql--> <select id= "queryscore" resulttype= "score" > select degree from test.score where sno = #{sno} </select> |
在標(biāo)簽中
- property 指向了 student.java 中新增的 score 字段。
- column 指定了作為參數(shù)傳遞給下一個(gè)查詢sql的字段,需要注意的是對(duì)于傳遞單個(gè)字段的情況,mybatis 只是簡(jiǎn)單的將 #{參數(shù)} 替換為占位符 ?, 然后執(zhí)行 resultset.getstring(columnname),沒有進(jìn)行參數(shù)匹配,因此第二個(gè) sql 中 #{} 中寫任何字符都可以;如果需要傳遞多個(gè)字段,使用 column = " {prop1=col1,prop2=col2} ",這種情況下會(huì)以參數(shù)對(duì)象的形式來傳遞。
- select 指定了下一個(gè) select 語句
另外需要注意的是這種嵌套查詢對(duì)于大型結(jié)果集和列名并友好,存在 n+1 的問題,因?yàn)橄乱粭l sql 會(huì)執(zhí)行 n 次去循環(huán)查詢,使用關(guān)聯(lián)查詢更合適。再者也可以開啟 mybatis 的懶查詢功能,嵌套的 sql 不是一口氣順序執(zhí)行完,而是在使用的時(shí)候才會(huì)執(zhí)行下一條 sql。例如執(zhí)行student.getscore().getsno()才會(huì)執(zhí)行queryscore的 sql。默認(rèn)情況下沒有開啟,需要在配置文件中設(shè)置
設(shè)置參數(shù) | 描述 | 默認(rèn)值 |
---|---|---|
lazyloadingenabled | 延遲加載的全局開關(guān),特定關(guān)聯(lián)關(guān)系中可通過設(shè)置 fetchtype 屬性來覆蓋該項(xiàng)的開關(guān)狀態(tài) | false |
aggressivelazyloading | 當(dāng)開啟時(shí),任何方法的調(diào)用都會(huì)加載該對(duì)象的所有屬性。否則,每個(gè)屬性會(huì)按需加載 | false (true in ≤3.4.1) |
1
2
3
|
<!--mybatis-config.xml--> <setting name= "lazyloadingenabled" value= "true" /> <setting name= "aggressivelazyloading" value= "false" /> |
也可以在標(biāo)簽中設(shè)置 fetchtype = “lazy” 開啟懶加載,會(huì)覆蓋全局的參數(shù)設(shè)置。
嵌套結(jié)果集
對(duì)于多表關(guān)聯(lián)查詢,一般在 sql 中使用別名來避免字段名的重復(fù)。mybatis 要做的是將別名正確的映射到 javabean 屬性上。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<!--嵌套結(jié)果--> <resultmap id= "associationdemomap" type= "student" automapping= "true" > <association property= "score" javatype= "score" > <result property= "sno" column= "sc_sno" /> </association> </resultmap> <select id= "querystudentscore" resultmap= "associationdemomap" > select sname, ssex, class , st.sno, sc.sno as sc_sno from test.student st inner join test.score sc on st.sno = sc.sno where cno = '3-105' ; </select> |
通過設(shè)置標(biāo)簽指定了表列名和屬性之間的映射關(guān)系。但這樣如果字段很多,會(huì)需要一一指定,標(biāo)簽提供了columnprefix屬性,指定別名的前綴,這樣可以重用resultmap
1
2
3
4
5
6
7
8
|
<resultmap id= "associationdemomap" type= "student" automapping= "true" > <!--columnprefix 指定別名的前綴--> <association property= "score" resultmap= "anothermap" columnprefix= "sc_" /> </resultmap> <!--方便重用--> <resultmap id= "anothermap" type= "score" automapping= "true" > </resultmap> |
一對(duì)多關(guān)系
除了一對(duì)一的關(guān)系,還有一對(duì)多的關(guān)系,比如這里一個(gè)學(xué)生student 對(duì)應(yīng)多門課的成績(jī)。 一對(duì)多對(duì)應(yīng)的情況下要在 resultmap 中使用 標(biāo)簽。首先需要調(diào)整 javabean 文件中兩個(gè)表之間的關(guān)系。
1
2
3
4
5
6
7
8
|
<!--student.java--> private list<score> score; public list<score> getscore() { return score; } public void setscore(list<score> score) { this .score = score; } |
以嵌套結(jié)果集為例
1
2
3
4
5
6
7
8
9
10
11
12
|
<resultmap id= "collectiondemomap" type= "student" automapping= "true" > <!--多出了 oftype 屬性--> <collection property= "score" oftype= "score" > <result property= "sno" column= "sc_sno" /> </collection> </resultmap> <select id= "querystudentscore" resultmap= "collectiondemomap" > select sname,ssex, class ,st.sno,sc.sno as sc_sno from test.student st inner join test.score sc on st.sno = sc.sno </select> |
注意到相比 association 多了一個(gè)屬性oftype,是用來表示 list 集合中的類型的。其他屬性的用法同 association 是一樣的。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。
原文鏈接:https://juejin.im/post/5b63a710e51d4518f5443d23