首页 > 其他分享 >Mybatis10 - 多对一

Mybatis10 - 多对一

时间:2023-02-13 21:24:39浏览次数:34  
标签:Mybatis10 查询 dept emp 属性 id 加载

多表联查

员工-部门 一对多:员工中有一个属性存储部门对象

部门-员工 多对一:部门中有一个属性存储员工对象集合

一次查询,通过员工 id 查询员工信息以及所在部门信息

方法一:resultMap 逐个配置 字段与属性对象的属性之间的映射关系

接口类声明方法

Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);

配置 resultMap 设置字段与属性的映射关系

<resultMap id="empAndDeptResultMap" type="Emp">
    <!-- id 主键和属性映射关系-->
    <id column="emp_id" property="empId"></id>
    <!-- result 普通字段和属性映射关系-->
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>

    <!-- 属性为对象时,property = "对象.属性" -->
    <result column="dept_id" property="dept.deptId"></result>
    <result column="dept_name" property="dept.deptName"></result>

</resultMap>

SQL语句 左连接实现多表联查

<!--    Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
    SELECT t_emp.*, t_dept.dept_name
    FROM t_emp
    LEFT JOIN t_dept
    ON t_emp.dept_id = t_dept.dept_id
    WHERE t_emp.emp_id = #{empId}
</select>

测试方法

@Test
public void testGetEmpAndDeptByEmpId(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = mapper.getEmpAndDeptByEmpId(2);
    System.out.println(emp);
}

结果

Emp{empId=2, empName='李四', age=22, gender='男', dept=Dept{deptId=1, deptName='A'}}

方法二:resultMap 中使用 association 标签,专门处理实体类属性的多对一关系

association 和 collection 都是专门用于处理实体类型的属性的标签

配置 resultMap 中 association 标签,属性 映射到实体类,从而字段映射到实体类的属性

    <resultMap id="empAndDeptResultMap" type="Emp">
        <!-- id 主键和属性映射关系-->
        <id column="emp_id" property="empId"></id>
        <!-- result 普通字段和属性映射关系-->
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>

        <association property="dept" javaType="Dept">
            <id column="dept_id" property="deptId"></id>
            <result column="dept_name" property="deptName"></result>
        </association>

    </resultMap>

其他步骤同方法一

方法三:分步查询,适用于 >=2张表的联查,先查员工信息,获得 dept_id 再查部门信息

查询步骤一:员工 emp_id 查询员工信息,将信息中的部门 dept_id 作为参数传给第二步查询

接口类声明方法一

Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);

配置 resultMap 设置字段与属性的映射关系,以及调用第二步查询

<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <!-- id 主键和属性映射关系-->
    <id column="emp_id" property="empId"></id>
    <!-- result 普通字段和属性映射关系-->
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>

    <!--
        property 设置需要处理映射关系的属性的属性名
        select 定位分步查询的下一步查询,唯一标识= "namespace.id"
        column 将下一步查询需要的字段作为参数传入查询方法中
		select+column 就是调用方法+传参的过程
    -->
    <association property="dept"
                 select="com.zzz.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="dept_id"></association>
</resultMap>

SQL语句和单表查询员工信息相同

<!--    Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
    SELECT * FROM t_emp WHERE emp_id = #{empId}
</select>
查询步骤二:根据步骤一传入的参数 dept_id 查询部门信息,简单的单表查询

接口类声明方法二

Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);

部门的属性中没有实体类型的属性,不需要 resultMap (需要在mybatis核心配置文件中开启下划线自动转驼峰)

<!--    Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);-->
<select id="getEmpAndDeptByStepTwo" resultType="Dept">
    SELECT * FROM t_dept WHERE dept_id = #{deptId}
</select>
测试
@Test
public void testGetEmpAndDeptByEmpId(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = mapper.getEmpAndDeptByStepOne(1);
    System.out.println(emp);
}
结果
Emp{empId=1, empName='张三', age=20, gender='男', dept=Dept{deptId=1, deptName='A'}}
各个要素之间的对应关系

img

分步查询的优势 - 可以实现延迟加载

但是必须在核心配置文件中设置全局配置信息:

<!-- Mybatis全局配置 -->
<settings>

    <!-- 开启延迟加载功能 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 设置按需加载 -->
    <setting name="aggressiveLazyLoading" value="flase"/>
    
</settings>

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载

aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载

此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加载)|eager(立即加载)"

实现按需使用分步查询,如果没有获取第二步的信息,则只会执行第一步

测试,只获取员工信息

@Test
public void testGetEmpAndDeptByEmpId(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = mapper.getEmpAndDeptByStepOne(1);
    System.out.println(emp.getEmpName());
}

结果

DEBUG 02-13 17:10:28,875 ==>  Preparing: SELECT * FROM t_emp WHERE emp_id = ?  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:10:28,910 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:10:28,982 <==      Total: 1  (BaseJdbcLogger.java:137) 
张三

从结果中可以看出,只执行了分步查询的第一步: SELECT * FROM t_emp WHERE emp_id = ?

关闭懒加载:执行所有步骤

DEBUG 02-13 17:11:42,451 ==>  Preparing: SELECT * FROM t_emp WHERE emp_id = ?  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:11:42,483 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:11:42,515 ====>  Preparing: SELECT * FROM t_dept WHERE dept_id = ?  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:11:42,516 ====> Parameters: 1(Integer)  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:11:42,519 <====      Total: 1  (BaseJdbcLogger.java:137) 
DEBUG 02-13 17:11:42,519 <==      Total: 1  (BaseJdbcLogger.java:137) 
张三

在开启了延迟加载后,可以在 association 标签中为单个 resultMap设置为立即加载

fetchType="eager|lazy" eager-立即加载, lazy-延迟加载(默认)

<association property="dept"
             fetchType="eager"
             select="com.zzz.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
             column="dept_id"></association>

标签:Mybatis10,查询,dept,emp,属性,id,加载
From: https://www.cnblogs.com/Ashen-/p/17117825.html

相关文章