在上一篇文章 MyBatis | 映射文件之 ResultMap(一)中霍殴,簡述了如何使用 ResultMap,以及如何使用 ResultMap 進行一對一的關聯查詢刀诬。這一篇我將說明如何使用 ResultMap 進行一對多的關聯查詢
一、說明與準備
為了便于學習,我仍然會貼出表結構和 POJO 的設計章姓,下面是實驗前的環(huán)境搭建
employee 的 dept_id 關聯 department 表的 id 字段,即 id 是 dept_id 的外鍵识埋。這和上一篇的創(chuàng)建是一致的
Employee.java
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Department department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
...
}
Department:這里我設置了一個類型為 Employee 的 List 集合凡伊,對應數據庫表中一個部門可以有多個員工
public class Department {
private Integer id;
private String departName;
private List<Employee> employees;
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public List<Employee> getEmployees() {
return employees;
}
...
}
二、使用 ResultMap 進行一對多關聯查詢
需求是窒舟,使用 sql 語句系忙,查詢出每個部門的信息,以及每個部門所關聯的員工信息惠豺。由于一個部門對應多個員工银还,即一對多风宁,這里我們使用 LEFT JOIN 對字段進行連接
1. 使用 collection 進行兩張表的關聯查詢
類似于上一篇中介紹的一對一的關聯查詢,不過上一篇中關聯的是一個對象蛹疯,不這里關聯的是一個集合戒财。至于 collection
,我會結合代碼進行講解
①. 首先創(chuàng)建一個集合類
DepartmentMapper.java
public interface DepartmentMapper {
public Department getDepartmentAndList(Integer id);
}
②. 配置 sql 映射文件
下面是 DepartmentMapper.xml 的配置信息捺弦,sql 語句如下饮寞,當然是使用外鍵關聯
<select id="getDepartmentAndList" resultMap="dept">
SELECT d.id did, d.depart_name, e.id eid, e.last_name, email, gender
FROM department d
LEFT JOIN employee e
ON d.id = e.dept_id
WHERE d.id = #{id}
</select>
接下來寫 resultMap 的配置:外層的 id 和 result 標簽,是配置 Department 類(表)的列吼,collection 標簽里面的 id 和 result 標簽骂际,都是用來配置與 Department 類關聯的 Employee 類(表)的。(PS:由于我在 mybatis.xml 主配置文件中配置了使用別名冈欢,因此類型都是以別名顯示歉铝。否則需要全類名。)
collection
標簽里定義的集合對象凑耻,這里定義的是 Employee 類型的集合
property
:指定 Department 對象里面包含的 Employee 集合對象太示,即 List<Employee> employees
ofType
:指定集合的類型
<!-- 使用嵌套結果集的方式, 使用 collection 標簽定義關聯的集合類型的封裝規(guī)則 -->
<resultMap type="Department" id="dept">
<!-- Deparment 類的配置 -->
<id column="id" property="id"/>
<result column="depart_name" property="departName"/>
<!-- Employee 類的配置 -->
<collection property="employees" ofType="Employee">
<id column="id1" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
③. 結果
測試語句我不寫了,我們傳入 Employee 的 id 為 1香浩,直接貼出結果
Department [id=1, departName=開發(fā)部]
[Employee [id=1, lastName=Tom, email=tom@126.com, gender=0],
Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1],
Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1],
Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2]]
同時貼出使用同樣 sql 語句和同樣 id 的數據庫查詢的結果
+-----+-------------+------+-----------+--------------+--------+
| did | depart_name | eid | last_name | email | gender |
+-----+-------------+------+-----------+--------------+--------+
| 1 | 開發(fā)部 | 1 | Tom | tom@126.com | 0 |
| 1 | 開發(fā)部 | 2 | Peter | peter@qq.com | 1 |
| 1 | 開發(fā)部 | 7 | ljk | lkj@123.com | 1 |
| 1 | 開發(fā)部 | 15 | lkj | lkj@123.com | 2 |
+-----+-------------+------+-----------+--------------+--------+
可以看到类缤,使用 resultMap 查詢出來的結果和數據庫查詢的結果一致,而且 Employee 確實是以 List 集合的形式出現的邻吭。
???遇到的坑:
在查詢的過程中餐弱,遇到了一個畢竟大的坑??,當時找了快幾個小時╯︿╰囱晴,這里說明一下膏蚓,防患于未來。畸写。
先斬后奏把驮瞧。column 里面的值一定要與查詢出來的列名相一致, 如果使用列的別名, 則 column 的值就是列的別名
拿上面的 sql 為例,我們看一下使用別名查詢出來的列名
| did | depart_name | eid | last_name | email | gender |
以 id 這個字段為例子枯芬,我們注意一下 resultMap 里面配置的兩個 id 標簽對應的 column 對應的值论笔,可以看到對應的是 sql 語句(SELECT d.id did, e.id eid ... FROM department d...
)中設置的別名 did
和 eid
。
<resultMap type="Department" id="dept">
<id column="did" property="id"/>
...
<collection property="employees" ofType="Employee">
<id column="eid" property="id"/>
....
</collection>
</resultMap>
如果你沒有設置別名(SELECT d.id, e.id ... FROM department d...
)千所,同時你在兩個 id 標簽的 column 直接填 id狂魔,那么就會出問題。淫痰。血的教訓??
| id | depart_name | id1 | last_name | email | gender |
不用別名查詢出來的表的列名結構是這樣的最楷,如果真要用,可以這樣配置。這樣也是可以查詢出結果的管嬉,不過并不推薦皂林。還是使用別名把!r橇谩础倍!
<resultMap type="Department" id="dept">
<id column="d1" property="id"/>
...
<collection property="employees" ofType="Employee">
<id column="id1" property="id"/>
....
</collection>
</resultMap>
2. 使用 collection 進行兩張表的分布查詢
使用 association 進行分布查詢,實則分三步:
- 先根據部門 id 查詢出部門所有信息:
select * from department where id = ?
- 根據部門查詢出來的 id(外鍵)胎挎,用于查詢部門對應的多個員工信息:
select * from employee where dept_id = ?
- 將員工信息關聯到部門信息
先創(chuàng)建一個接口類
public interface DepartmentMapper {
public Department getDepartmentStep(Integer id);
}
查詢部門 Department 類的配置
<select id="getDepartmentStep" resultMap="empStep">
select id, depart_name from department where id = #{id}
</select>
查詢員工 Employee 類的配置
<select id="getEmployeeByDeptId" resultType="Employee">
select id, last_name, gender, email, dept_id from employee where dept_id = #{deptId}
</select>
配置 resultMap沟启,注意 collection 中的 column 屬性對應數據庫中的列名
<resultMap type="Department" id="empStep">
<!-- Department 類的配置 -->
<id column="id" property="id"/>
<result column="depart_name" property="departName"/>
<!--
使用 collection 定義分段的集合類型的屬性
-->
<collection property="employees"
select="edu.just.mybatis.dao.EmployeeMapper.getEmployeeByDeptId"
column="id">
</collection>
</resultMap>
結果:
[Employee [id=1, lastName=Tom, email=tom@126.com, gender=0, department=null],
Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1, department=null],
Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1, department=null],
Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2, department=null]]
3. 使用延遲加載
collection 標簽中的延遲加載比較簡單,直接在 collection 里面設置 fetchType
屬性值為 lazy
即可
fetchType="lazy"
表示使用延遲加載
fetchType="eager"
表示立即加載
<resultMap type="Department" id="empStep">
...
<collection property="employees"
...
fetchType="lazy">
</collection>
</resultMap>