MyBatis 中表的映射关系

多对多 和 一对一方法相同 ,这里不展开讲 ,主要讲解 一对多 和 多对一

resultMap的作用 : 处理属性和字段之间的映射关系 (设置自定义映射)

属性:

1
2
3
4
id:表示自定义映射的唯一标识 与select标签中的resultMap内容一致

type:查询的数据要映射的实体类的类型

子标签:

1
2
3
4
5
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系

属性:

1
2
3
4
property:设置映射关系中实体类中的属性名

column:设置映射关系中表中的字段名

First : 多对一的映射关系

查询员工以及员工所对应的部门信息 或者查询学生以及学生所对应的班级信息

本文讲解主要以员工类Emp以及部门类Dept为主,对应的数据库表名[ Emp—>t_emp ] [ Dept—> t_dept]

方法一 : 使用级联的方式处理映射关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<resultMap id="getEmpAndDept" type="Emp">
<!-- 这里是处理当前表emp的-->
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!-- 这里是处理Dept中的属性-->
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>

<!-- 接口 : Emp getEmpAndDeptById(@Param("empId") Integer empId); -->
<select id="getEmpAndDeptById" resultMap="getEmpAndDept">
select
t_emp.* ,t_dept.*
from t_emp left join t_dept
on t_emp.dept_id = t_dept.dept_id
where t_emp.emp_id = #{empId}
</select>

注意点: 这里的查询用到了左外连接, 多表查询的一种。

方法二 : 使用association标签: 处理映射关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<resultMap id="getEmpAndDeptOne" type="Emp">
<!-- 这里是处理表t_emp-->
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--
property 中处理的一定是实体类中的属性 所以Emp中的属性名有一个Dept 类型的dept
javaType===>是该属性的来源
-->
<!-- 这里是处理t_dept表-->
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<!-- Emp getEmpAndDeptById(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptById" resultMap="getEmpAndDeptOne">
select
t_emp.* ,t_dept.*
from t_emp left join t_dept
on t_emp.dept_id = t_dept.dept_id
where t_emp.emp_id = #{empId}
</select>

方法三 : 最常用的 分布查询

步骤:

  1. 首先查询相关的员工信息
  2. 根据员工信息中的部门id 从而查询出对应的部门信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<resultMap id="getEmpOne" type="Emp">

<!-- 这里是处理当前表emp的-->
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>

<!--这里的dept从哪里来,就是stepTwo(DeptMapper中的)中的查询出来的dept
property : 设置需要处理映射关系的属性的属性名
select : 设置分布查询的 sql语句的唯一表示 通过namespace.id : 获取sql语句的唯一标识
格式: 模块名.包名.接口名.方法名
column : 设置分布查询的sql的条件
也就是作为下一步StepTwo 的sql的条件where XXX = ? 的字段
-->
<association property="dept"
select="com_Ray.mapper.DeptMapper.getEmpStepTwo"
column="dept_id">
</association>
</resultMap>
<!-- 分布查询的第一步 Emp getEmpByStepOne(@Param("empId") Integer empId);-->
<select id="getEmpByStepOne" resultMap="getEmpOne">
select * from t_emp where emp_id = #{empId}
</select>

此时已经根据员工的id 查询出了相关的员工信息 , 接下来就是根据员工信息中的dept_id字段来查询出对应的部门的信息

再次解释assciation标签中的select属性: 设置分布查询的 sql语句的唯一表示 通过namespace.id获取

namespace 就是mapper标签中的属性 , 而对应的id 就是我们所要执行的接口中的方法名(因为方法名与id的内容要一致) image.png

image.png

接下来进行第二步:

1
2
3
4
5
6
<mapper namespace="com_Ray.mapper.DeptMapper">
<!-- 分布查询的第二步 Dept getEmpStepTwo(@Param("deptId") Integer deptId);-->
<select id="getEmpStepTwo" resultType="Dept">
select * from t_dept where dept_id = #{deptId}
</select>

分布查询的优点

可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息

1
2
3
4
5
6
7
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载

aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。
否则,每个属性会按需加载 ,此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。
此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,
fetchType="lazy(延迟加载)|eager(立即加载)"

Second : 一对多的映射关系

查询部门中所有的员工信息 或者查询班级中所有的学生信息

步骤:

  1. 首先在Dept部门类中创建Emp集合

image.png

  1. 然后再进行查询需要查询的部门id ,再通过部门id查询出部门中所有的员工信息

方法一 : collection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!--
collection : 处理多对一的属性
property : 需要处理的多对一的属性的属性名
ofType : 需要处理的属性的类型
注意点 :里面的emps是Emp的集合类型
-->
<resultMap id="deptResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>

<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<!--方法名: Dept getDeptById(@Param("deptId") Integer deptId);-->
<select id="getDeptById" resultMap="deptResultMap">
select
t_dept.* , t_emp.*
from t_emp right join t_dept
on t_emp.dept_id = t_dept.dept_id
where t_dept.dept_id = #{deptId}
</select>

方法二 : 分布查询

第一步:查询出需要查询的部门信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<resultMap id="DeptStepOne" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<!--
property : 设置需要处理映射关系的属性的属性名
select : 设置分布查询的 sql语句的唯一表示
通过namespace.id : 获取sql语句的唯一标识
column : 设置分布查询的sql的条件 作为下一步StepTwo 的sql的条件where XXX = ? 的字段
-->
<collection property="emps"
select="com_Ray.mapper.EmpMapper.getDeptByStepTwo"
column="dept_id">
</collection>
</resultMap>
<!-- 分布查询的第一步 : Emp getDeptByStepOne(@Param("deptId") Integer deptId);-->
<select id="getDeptByStepOne" resultMap="DeptStepOne">
select * from t_dept where dept_id = #{deptId}
</select>

第二步: 根据部门id 查询员工信息

1
2
3
4
5
6
<!-- 多对一 分布查询的二步
List<Emp> getDeptByStepTwo(@Param("deptId") Integer deptId); -->
<select id="getDeptByStepTwo" resultType="Emp">
select * from t_emp where dept_id = #{deptId}
</select>

注意点!!!

虽然这里我们用到的表中的字段名和所对应的实体类中的属性名不一致 ,但是表设置的字段名使用’_’符合数据库的规则, 而实体类中的属性也同样满足java驼峰命名规范,所以这里可以在核心控制文件中加上下面这段代码 ,这样就可以不用设置resultMap

1
2
3
4
   <settings>
<!-- mapUnderscoreToCamelCase: 将下划线映射为驼峰 例如: user_name==>userName -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>