MyBatis⑥ResultMap、多表查询
1、ResultMap 介绍
1.1、结果映射
结果映射:将 DQL 查询结果的字段映射到 Java 属性。
原则:自动映射简单关系,ResultMap 配置复杂关系。
- 简单关系:名称相同,类型匹配。
- 复杂关系
- 名称不相同:配置名称映射关系。
- 类型不匹配:多表查询。
1.2、ResultMap 配置
注:只需配置复杂关系,MyBatis 会自动映射简单关系。
- 配置:ResultMap 建立数据库表字段与 Java 实体类属性的映射关系。
- 使用:select 标签的 resultMap 属性,引入对应 id 的 resultMap。
1.2.1、标签属性
-
resultMap
- id:标识 ResultMap。
- type:数据库表所映射的 Java 实体类(全限类名或别名)。
-
result
-
column:数据库表的字段名(或别名)。
-
property:字段所映射的 Java 属性名。
<resultMap id="" type="映射的实体类名"> <result column="数据库表字段" property="实体类属性"/> <result column="数据库表字段" property="实体类属性"/> </resultMap>
-
1.2.1、使用示例
名称不相同
- MyBatis 核心配置文件的
settings
,可开启自动映射mapUnderscoreToCamelCase
。- 本质是建立 ResultMap,处理数据库表字段和实体类属性之间的映射关系。
示例:将数据库表的 user_id 映射为 Java 实体类的 userId。
<resultMap id="userMap" type="user">
<result column="user_id" property="userId"/>
</resultMap>
<select id="getUserById" resultMap="userMap">
SELECT user_id, name, password
FROM t_user
</select>
类型不匹配
涉及多表查询:
- 多对一:多个 A 对应一个 B(关联)
- 一对多:一个 A 对应多个 B(集合)
2、多表查询
一对多和多对一,是基于不同角度描述的相对关系。
示例:部门和员工的关系。
- 多对一:多个员工属于一个部门(关联)
- 一对多:一个部门包含多个员工(集合)
数据库表
在 “一” 的数据库表中建立 “多” 的逻辑外键。
-
部门表
-
员工表:建立逻辑外键,即部门 ID
实体类
在 “一” 的实体类中建立 “多” 的对象类型(而不仅仅是主键)。
-
部门类
public class Department { private String deptId; private String name; }
-
员工类:通过 Department 类表示部门,而不是 deptId。
public class Employee { private String empId; private String name; private Department department; }
2.1、多对一
需求:查询所有员工,及所属的部门信息。
List<Employee> listEmployees();
- 在数据库表中以 dept_id 表示,在实体类中以 Department 表示。
- 通过 resultMap 的
association
标签,建立关联关系。- 结合子查询
- 结合联表查询
2.1.1、子查询
EmployeeMapper.xml
-
listEmployees
- 查询 employee 表
- 引用 resultMap,而不是 resultType
-
resultMap - association:建立关联关系,将数据库表的 dept_id 映射为 Department
- column:数据库表的字段名。
- property:实体类的属性名。
javaType
:映射的 Java 类型(全限类名或别名)。select
:引用子查询。
-
子查询:
#{}
占位符参数,由 resultMap 的 column 提供。<select id="listEmployees" resultMap="employeeMap"> SELECT emp_id, name, dept_id FROM study_mysql.t_employee </select> <resultMap id="employeeMap" type="indi.jaywee.pojo.Employee"> <association column="dept_id" property="department" javaType="indi.jaywee.pojo.Department" select="getDepartmentById"/> </resultMap> <select id="getDepartmentById" resultType="indi.jaywee.pojo.Department"> SELECT dept_id, name FROM study_mysql.t_department WHERE dept_id = #{dept_id} </select>
等价 SQL
结合子查询的方式,相当于:
SELECT e.emp_id AS e_id,
e.name AS e_name,
e.dept_id AS d_id,
(SELECT d.name
FROM t_department
WHERE dept_id = d_id)
FROM t_employee AS e;
2.1.2、联表查询
EmployeeMapper.xml
-
listEmployees
- 联表查询:查询 employee 和 department 表,起别名(因为两个表有同名属性)
- 引用 resultMap,而不是 resultType。
-
resultMap
-
result
- column:数据库表的字段名。
- property:实体类的属性名。
-
association:建立关联关系,将数据库表的 dept_id 映射为 Department。
-
property:实体类的属性名。
-
javaType
:映射的 Java 类型(全限类名或别名)。<select id="listEmployees" resultMap="employeeMap"> SELECT e.emp_id AS e_id, e.name AS e_name, e.dept_id AS d_id, d.name AS d_name FROM study_mysql.t_employee AS e LEFT JOIN study_mysql.t_department AS d ON e.dept_id = d.dept_id </select> <resultMap id="employeeMap" type="indi.jaywee.pojo.Employee"> <result column="e_id" property="empId"/> <result column="e_name" property="name"/> <association property="department" javaType="indi.jaywee.pojo.Department"> <result column="d_id" property="deptId"/> <result column="d_name" property="name"/> </association> </resultMap>
-
-
2.2、一对多
需求:查询所有部门,及部门下的所有员工信息。
List<Department> listDepartments();
- 数据库 department 表中没有关于员工的字段,需要通过 dept_id 查询 employee 表。
- 通过 resultMap 的
collection
标签,建立集合关系。- 结合子查询
- 结合联表查询
实体类
-
员工:此处省略对部门属性的配置。
-
部门:添加 List 成员变量,表示部门所包含的员工。
private List<Employee> employeeList;
2.2.1、子查询
DepartmentMapper.xml
-
listDepartments
- 查询 deparment 表
- 引用 resultMap,而不是 resultType
-
resultMap - collection:建立集合关系
- column:数据库表的字段名,作为子查询的查询条件。
- property:实体类的属性名。
javaType
:集合类型,可省略(全限类名或别名)ofType
:实际映射的 Java 类型(全限类名或别名)select
:引用子查询。
-
子查询:
#{}
占位符参数,由 resultMap 的 column 提供。<select id="listDepartments" resultMap="departmentMap"> SELECT emp_id, name, dept_id FROM study_mysql.t_employee </select> <resultMap id="departmentMap" type="indi.jaywee.pojo.Department"> <collection column="dept_id" property="employeeList" javaType="java.util.List" ofType="indi.jaywee.pojo.Employee" select="listEmployeesByDeptId"/> </resultMap> <select id="listEmployeesByDeptId" resultType="indi.jaywee.pojo.Employee"> SELECT emp_id, name FROM study_mysql.t_employee WHERE dept_id = #{dept_id} </select>
2.2.2、联表查询
DepartmentMapper
-
listEmployees
- 联表查询:查询 department 和 employee 表,起别名(因为两个表有同名属性)
- 引用 resultMap,而不是 resultType
-
resultMap
-
result
- column:数据库表的字段名。
- property:实体类的属性名。
-
collection:建立集合关系
-
property:实体类的属性名。
-
javaType
:集合类型,可省略(全限类名或别名)。 -
ofType
:实际映射的 Java 类型(全限类名或别名)<select id="listDepartments" resultMap="departmentMap"> SELECT d.dept_id AS d_id, d.name AS d_name, e.emp_id AS e_id, e.name AS e_name FROM study_mysql.t_department AS d LEFT JOIN study_mysql.t_employee AS e ON d.dept_id = e.dept_id </select> <resultMap id="departmentMap" type="indi.jaywee.pojo.Department"> <result column="d_id" property="deptId"/> <result column="d_name" property="name"/> <collection property="employeeList" ofType="indi.jaywee.pojo.Employee"> <result column="e_id" property="empId"/> <result column="e_name" property="name"/> </collection> </resultMap>
-
-
2.3、小结
多对一和一对多关系,是基于不同角度描述的相对关系。
- 多对一:关联(association),
javaType
表示映射对象。 - 一对多:集合(collection),
ofType
表示映射对象。
通过 resultMap 标签,建立复杂关系的映射关系。
- 子查询:
- 查出当前表的属性,封装到当前对象。
- 根据逻辑外键进行子查询,在子查询中封装关联对象。
- 联表查询:推荐
- 查出所有表的属性,起别名。
- 通过 resultMap 配置所有映射关系。