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