8、Mybatis之自定义映射
阅读原文时间:2023年08月21日阅读:6

8.1.1、创建新module

创建名为mybatis_resultMap的新module,过程参考5.1节

8.1.2、创建t_emp和t_dept表

CREATE TABLE `t_emp` (
  `emp_id` int(11) NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `gender` char(1) DEFAULT NULL,
  `dept_id` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `t_dept` (
  `dept_id` int(11) NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

8.1.3、创建Emp实体类

package org.rain.mybatis.pojo;

/**
 * @author liaojy
 * @date 2023/6/7 - 0:11
 */
public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

8.1.4、创建Dept实体类

package org.rain.mybatis.pojo;

/**
 * @author liaojy
 * @date 2023/6/7 - 0:17
 */
public class Dept {

    private Integer deptId;
    private String deptName;

    public Dept() {
    }

    public Dept(Integer deptId, String deptName) {
        this.deptId = deptId;
        this.deptName = deptName;
    }

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptId=" + deptId +
                ", deptName='" + deptName + '\'' +
                '}';
    }
}

8.1.5、创建Mapper接口和映射文件

++++++++++++++++++++++++++++分割线++++++++++++++++++++++++++++

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.rain.mybatis.mapper.EmpMapper">

</mapper>

8.1.6、创建测试类

8.2.1、接口方法

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

8.2.2、映射文件

    <!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpId" resultType="Emp">
        select * from t_emp where emp_id = #{empId}
    </select>

8.2.3、测试方法

    @Test
    public void testGetEmpByEmpId(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = empMapper.getEmpByEmpId(1);
        System.out.println(emp);
        sqlSession.close();
    }

8.2.4、执行效果

注意:与字段名不匹配的属性值为null

8.2.5、映射文件纠正

8.2.5.1、方式一:设置别名

    <!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpId" resultType="Emp">
        <!-- select * from t_emp where emp_id = #{empId} -->
        select emp_id empId ,emp_name empName,age,gender from t_emp where emp_id = #{empId}
    </select>

8.2.5.1、方式二:使用自定义映射

    <!--
        resultMap标签:设置自定义映射
        id属性:表示自定义映射的唯一标识
        type属性:查询的数据要映射的实体类类型

        子标签:
        id:设置主键的映射关系
        result:设置普通字段的映射关系
        子标签属性:
        property:设置映射关系中实体类的属性名
        column:设置映射关系中表的字段名
    -->
    <resultMap id="empResultMap" type="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>
    </resultMap>

    <!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
    <!--
        resultMap属性:设置要使用的自定义映射
    -->
    <select id="getEmpByEmpId" resultMap="empResultMap">
        select * from t_emp where emp_id = #{empId}
    </select>

8.3.1、实体类调整

注意:在多(员工)对一(部门)关系中,(员工)实体类有一个(部门)对象

package org.rain.mybatis.pojo;

/**
 * @author liaojy
 * @date 2023/6/7 - 0:11
 */
public class Emp {

    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    private Dept dept;

    public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", dept=" + dept +
                '}';
    }
}

8.3.2、接口方法

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

8.3.3.、测试方法

    @Test
    public void testGetEmpAndDeptByEmpId(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = empMapper.getEmpAndDeptByEmpId(1);
        System.out.println(emp);
        sqlSession.close();
    }

8.3.4、映射文件

8.3.4.1、方式一:级联

注意:字段不能匹配对象,只能匹配对象中的属性;因此使用级联方式时,property值的形式为:对象名.属性名

    <resultMap id="empAndDeptResultMap" type="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>
        <result column="dept_id" property="dept.deptId"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>

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

8.3.4.2、方式二:association标签

比起级联方式,使用association标签的层次更加分明

    <resultMap id="empAndDeptResultMap" type="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>
        <!--
            association标签:设置多对一的映射关系,用于处理实体类类型的属性
            property属性:设置要处理的实体类属性名
            javaType属性:设置要处理的实体类属性的类型(此处和resultType一样可以使用实体类类型别名)
        -->
        <association property="dept" javaType="Dept">
            <id column="dept_id" property="deptId"></id>
            <result column="dept_name" property="deptName"></result>
        </association>
    </resultMap>

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

8.4.1、实体类调整

注意:在一(部门)对多(员工)关系中,(部门)实体类有一个(员工)对象集合

package org.rain.mybatis.pojo;

import java.util.List;

/**
 * @author liaojy
 * @date 2023/6/7 - 0:17
 */
public class Dept {

    private Integer deptId;
    private String deptName;

    private List<Emp> emps;

    public Dept() {
    }

    public Dept(Integer deptId, String deptName) {
        this.deptId = deptId;
        this.deptName = deptName;
    }

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptId=" + deptId +
                ", deptName='" + deptName + '\'' +
                ", emps=" + emps +
                '}';
    }
}

8.4.2、接口方法

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

8.4.3、测试方法

    @Test
    public void testGetDeptAndEmpByDeptId(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = deptMapper.getDeptAndEmpByDeptId(1);
        System.out.println(dept);
        sqlSession.close();
    }

8.4.4、映射文件

注意:一对多映射关系,不能使用级联的方式处理

    <resultMap id="deptAndEmpResultMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <!--
            collection标签:设置一对多映射关系,用于处理集合类型的属性
            property属性:设置要处理的集合类型属性名
            ofType属性:设置要处理的集合类型属性中存储的(实体类)数据类型
        -->
        <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 getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
        select * from t_dept left join t_emp on t_dept.dept_id = t_emp.dept_id where t_dept.dept_id = #{deptId}
    </select>

8.5.1、多对一的分步查询

8.5.1.1、接口方法

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

+++++++++++++++++++++++分割线+++++++++++++++++++++++

注意:返回类型,和要查询的属性类型一致。

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

8.5.1.2、映射文件

    <!--Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);-->
    <select id="getEmpAndDeptByStepTwo" resultType="Dept">
        select * from t_dept where dept_id = #{deptId}
    </select>

+++++++++++++++++++++++分割线+++++++++++++++++++++++

    <resultMap id="empAndDeptBySetpResultMap" type="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属性:设置要处理的实体类属性名
            select属性:设置分布查询的SQL的唯一标识,用于查询实体类属性的值
            column属性:设置某个字段作为分布查询的SQL的条件
        -->
        <association property="dept" select="org.rain.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="dept_id">
        </association>
    </resultMap>

    <!--Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);-->
    <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptBySetpResultMap">
        select * from t_emp where emp_id = #{empId}
    </select>

8.5.1.3、核心配置文件

注意:该全局配置是为了简化手动映射下划线和驼峰的关系;当已使用resultMap手动映射下划线和驼峰的关系,则可以不使用该全局配置

    <settings>
        <!--将下划线映射为驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

8.5.1.4、测试方法

    @Test
    public void testGetEmpAndDeptByStep(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = empMapper.getEmpAndDeptByStepOne(1);
        System.out.println(emp);
        sqlSession.close();
    }

8.5.1.5、执行效果

由控制台日志可知,该分步查询执行了两次SQL

8.5.2、延迟加载

8.5.2.1、核心配置文件

注意:开启延迟加载的前提是aggressiveLazyLoading的全局配置值为false,即

由于Mybatis 3.4.1之后版本的aggressiveLazyLoading默认值就是false,所以可省略

    <settings>
        <!--开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

8.5.2.2、执行效果

注意:分步查询的优点是可以实现延迟加载;由控制台日志可知,当第一步的查询SQL满足需要时,第二步的查询SQL不会执行

8.5.2.3、局部配置延迟加载

    <resultMap id="empAndDeptBySetpResultMap" type="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>
        <!--
            fetchType属性:设置当前的分步查询是否使用延迟加载;eager为立即加载,lazy为延迟加载
        -->
        <association property="dept" fetchType="lazy"
                     select="org.rain.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="dept_id">
        </association>
    </resultMap>

8.5.3、一对多的分步查询

8.5.3.1、接口方法

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

+++++++++++++++++++++++分割线+++++++++++++++++++++++

注意:返回类型,和要查询的属性类型一致。

List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);

8.5.3.2、映射文件

    <!--List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpByStepTwo" resultType="Emp">
        select * from t_emp where dept_id = #{deptId}
    </select>

+++++++++++++++++++++++分割线+++++++++++++++++++++++

    <resultMap id="deptAndEmpByStepResultMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" select="org.rain.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="dept_id">
        </collection>
    </resultMap>

    <!--Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpByStepResultMap">
        select * from t_dept where dept_id = #{deptId}
    </select>

8.5.3.3、测试方法

    @Test
    public void testGetDeptAndEmpByStep(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = deptMapper.getDeptAndEmpByStepOne(1);
        System.out.println(dept);
        sqlSession.close();
    }

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器