【MyBatis系列】基础篇——ResultMap自定义映射
【前言】
resultType属性指定查询结果的返回值类型,来让MyBatis自动将查询结果集封装成我们希望的类型进行返回。
resultType属性非常有用,但在返回结果类型比较复杂的情况下却无能为力,为此,MyBatis在select元素中还为我们提供了另外一个resultMap属性,用于引用一个使用<resultMap/>
元素定义好的自定义结果集映射规则。
<resultMap/>
算是MyBatis中最重要、最强大的元素了,它可以让你比使用JDBC调用结果集省掉90%的代码,也可以让你做许多JDBC不支持的事。 事实上,编写类似的对复杂语句联合映射的代码也许会需要上千行。resultMap的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。
- 自定义resultMap,实现高级结果集映射
- id :用于完成主键值的映射
- result :用于完成普通列的映射
- association :一个复杂的类型关联;许多结果将包成这种类型
- collection : 复杂类型的集
【正文】
一、单表查询
实际上,单表查询直接使用resultMap即可,没必要用resultMap自定义映射,这里仅做一个简单的演示。
接口类:
/**
* 根据id查询员工信息
* @param id
* @return
*/
public Employee getEmployeeResultMap(int id);
mapper:
<!--根据id查询员工信息-->
<select id="getEmployeeResultMap" resultMap="myMap1">
select id,last_name from tbl_employee where id=#{id}
</select>
<resultMap id="myMap1" type="com.mybatislearn.entity.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
</resultMap>
结果:
二、多表查询
现有部门表和员工表,表结构如下:
题目一: 根据员工id查询 员工信息 及 员工所在部门信息
方式一:使用 id & result 标签
- id :用于完成主键值的映射
- result :用于完成普通列的映射
实体类:
员工表:
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
//部门对象属性
private Dept dept;
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
部门表:
public class Dept {
private Integer did;
private String dname;
//某个部门有很多个员工
private List<Employee> list;
@Override
public String toString() {
return "Dept{" +
"did=" + did +
", dname='" + dname + '\'' +
", list=" + list +
'}';
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public List<Employee> getList() {
return list;
}
public void setList(List<Employee> list) {
this.list = list;
}
}
接口类:
/**
* 根据id查询员工及其所属部门信息
* @param id
* @return
*/
public Employee getEmployeeAndDept(int id);
mapper.xml:
<!--根据id查询员工及其所属部门信息-->
<select id="getEmployeeAndDept" resultMap="myEmpAndDept">
SELECT * FROM tbl_dept d,tbl_employee e WHERE d.`did`=e.`did` AND e.`id`=#{id}
</select>
<!--自定义映射-->
<resultMap id="myEmpAndDept" type="com.mybatislearn.entity.Employee">
<!--员工表对应关系-->
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--部门表对应关系-->
<result column="did" property="dept.did"/>
<result column="dname" property="dept.dname"/>
</resultMap>
方式二:使用 association 标签
- association :一个复杂的类型关联;许多结果将包成这种类型;
(1)association
<!--自定义映射-->
<resultMap id="myEmpAndDept" type="com.mybatislearn.entity.Employee">
<!--员工表对应关系-->
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--部门表对应关系-->
<association property="dept" javaType="com.mybatislearn.entity.Dept">
<id column="did" property="did"/>
<result column="dname" property="dname"/>
</association>
</resultMap>
(2)association 分步查询
分两步:
① 先通过员工的id查询员工信息;
② 再通过查询出来的员工信息中的外键(部门id)查询对应的部门信息;
接口类:
/**
* 根据部门id查询部门信息
* @param did
* @return
*/
public Dept getDeptById(int did);
/**
* 根据员工id查询员工信息
* @param id
* @return
*/
public Employee getEmployeeAndDeptStep(int id);
mapper:
<!--根据部门id查询部门信息-->
<select id="getDeptById" resultType="com.mybatislearn.entity.Dept">
select * from tbl_dept where did=#{did}
</select>
<!--根据员工id查询员工信息-->
<select id="getEmployeeAndDeptStep" resultMap="myEmpAndDeptStep">
select * from tbl_employee where id=#{id}
</select>
<resultMap id="myEmpAndDeptStep" type="com.mybatislearn.entity.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--员工所属部门
select:查询员工所属部门的方法
fetchType:是否延迟 lazy:延迟 eager:不延迟
-->
<association property="dept" select="com.mybatislearn.mapper.EmployeeMapper.getDeptById"
column="did" fetchType="eager">
</association>
</resultMap>
结果:
(3)association 分步查询 使用延迟加载
- 在分步查询的基础上,可以使用延迟加载来提升查询的效率,也称懒惰查询,现在一般都不用这个技术了,有更先进的技术如elasticsearch等其他来代替;
- 用法: 只需要在全局的Settings中进行如下的配置;并在mapper里
fetchType="lazy"
(属性改为lazy)
mybatis-config.xml:
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置加载的数据是按需还是全部 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
此时,如果值调用方法,不打印数据的话,就会只调用一个方法:
不打印结果:
打印结果:
说明:
延迟加载是只在用的时候才加载,可以在一定方面提升效率。
题目二:根据id查询 部门信息 和 该部门所有员工信息
方式三:使用 collection 标签
- collection : 复杂类型的集;
(1)collection
实体类:
//某个部门有很多个员工
private List<Employee> emps;
接口:
/**
* 根据部门id查询 部门信息 和 部门所有员工信息
* @param did
* @return
*/
public Dept getDeptAndEmpsById(int did);
mapper:
<!--根据部门id查询 部门信息 和 部门所有员工信息-->
<select id="getDeptAndEmpsById" resultMap="myDeptAndEmp">
SELECT * FROM tbl_dept d LEFT JOIN tbl_employee e ON d.`did`=e.`did` WHERE d.`did`=#{did}
</select>
<resultMap id="myDeptAndEmp" type="com.mybatislearn.entity.Dept">
<id column="did" property="did"/>
<result column="dname" property="dname"/>
<!--关联:一个部门中有很多员工-->
<collection property="emps" ofType="com.mybatislearn.entity.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
实现类:
Dept dept = mapper.getDeptAndEmpsById(1);
System.out.println(dept);
结果:
(2)collection 分步查询
分两步:
① 先通过部门的id查询部门信息
② 再通过部门id作为员工的外键查询对应的部门信息
mapper:
<select id="getDeptAndEmpsByIdStep" resultMap="myDeptAndEmpsStep">
select id ,dept_name from tbl_dept where id = #{id}
</select>
<resultMap type="com.mybatislearn.mybatis.beans.Department" id="myDeptAndEmpsStep">
<id column="id" property="id"/>
<result column="dept_name" property="departmentName"/>
<collection property="emps"
select="com.mybatislearn.mybatis.dao.EmployeeMapper.getEmpsByDid"
column="did">
</collection>
</resultMap>
(3)collection 分步查询 使用延迟加载
用法同association:
在全局的Settings中进行配置;
并在mapper里fetchType="lazy"
;
三、拓展
(1)分步查询多列值的传递
- 如果分步查询时,需要传递给调用的查询中多个参数,则需要将多个参数封装成Map来进行传递,语法如下:
{k1=v1, k2=v2....}
; - 在所调用的查询方,取值时就要参考Map的取值方式,需要严格的按照封装map时所用的key来取值;
(2) association 或 collection的 fetchType属性
- 在
<association>
和<collection>
标签中都可以设置 fetchType 属性,指定本次查询是否要使用延迟加载;
默认为fetchType=”lazy”
,如果本次的查询不想使用延迟加载,则可设置为fetchType=”eager”
; - fetchType 属性可以灵活的设置查询是否需要使用延迟加载,而不需要因为某个查询不想使用延迟加载将全局的延迟加载设置关闭;
【结语】
感谢阅读哇~