Java框架 MyBatis自定义映射resultMap

0、准备工作

1、引入依赖


		
		
			org.mybatis
			mybatis
			3.5.7
		

		
		
			junit
			junit
			4.12
			test
		

		
		
			mysql
			mysql-connector-java
			8.0.27
		

		
		
			log4j
			log4j
			1.2.17
		
	

2、创建数据表

CREATE TABLE t_dept(
	dept_id INT PRIMARY KEY AUTO_INCREMENT,
	dept_name VARCHAR(20)
);

CREATE TABLE t_emp(
	emp_id INT PRIMARY KEY AUTO_INCREMENT,
	emp_name VARCHAR(20),
	age INT,
	gender CHAR,
	dept_id INT
);

INSERT INTO t_dept(dept_name) VALUES ('A'),('B'),('C');

INSERT INTO t_emp(emp_name,age,gender,dept_id) VALUES
('张三',20,'女',1),
('李四',22,'女',2),
('王五',21,'男',3),
('赵六',23,'男',1),
('田七',21,'女',3);

3、创建与数据表相对应 java 实体类

public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;
    private Integer deptId;

    public Emp() {
    }

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

    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 Integer getDeptId() {
        return deptId;
    }

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

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", deptId=" + deptId +
                '}';
    }
}
public class Dept {
    private Integer deptId;
    private String deptName;

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

    public Dept() {
    }

    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 + '\'' +
                '}';
    }
}

4、jdbc.properties 文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.username=root
jdbc.password=root

5、MyBaits 核心配置文件




	

	
	

	
		
	

	
	
		
			
			
				
				
				
				
			
		

	

	
	
		
		
	

6、工具类:

package com.chenyin.ssm.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

public class SqlSessionUtil {

    public static SqlSession getSqlSession() {
        try {
            // 获取核心的配置文件
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            // 创建 SqlSessionFactoryBuilder 对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

            // 通过核心配置文件多对应的字节输入流创建工厂类 SqlSessionFactory ,生产 SqlSession 对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);

            // 创建 SqlSession 对象(自动操作事务)
            return sqlSessionFactory.openSession(true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

7、log4j.xml配置文件






	
		
		
			
		
	
	
		
	
	
		
	
	
		
		
	

1、字段名和属性名不一致的情况

字段名和属性名不一致的情况,如何处理映射关系:

        1、为查询的字段设置别名,和属性名一致

        2、当字段符合 MySql 的要求使用,而属性符合 java 的要求使用驼峰,此时可以在 MyBatis 的核心文件中使用 setting 标签设置一个全局变量配置,可以自动将下划线映射为驼峰

        如:emp_id -> empId

        3、使用 resultMap 自定义映射处理

                resultMap:设置自定义的映射关系

                        id:唯一表示

                        type:处理映射关系的实体类的类型

                常用标签

                        id: 处理主键和实体类中属性的映射关系

                        result:处理普通字段和实体类中属性的映射关系

                        column:设置映射关系中的字段名,必须是sql 查询出的某个字段

                        property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名

                          

1.1、使用全局配置

代码示例:

EmpMapper 接口:

public interface EmpMapper {
    /**
     *  根据 empId 获取 emp 信息
     * @param empId
     * @return
     */
    Emp getEmpById(@Param("empId") Integer empId);
}

EmpMapper.xml 配置文件:






	

	

配置核心文件:

	
	
		
	

测试类:

public class EmpMapperTest {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
    DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);

    @Test
    public void getEmpById() {
        Emp emp = empMapper.getEmpById(2);
        System.out.println(emp);
        // Emp{empId=2, empName='李四', age=22, gender='女', deptId=2}
    }
}

1. 2、resultMap处理字段和属性的映射关系

EmpMapper 接口:

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

EmpMapper.xml 配置文件:





	
		
		
		
		
		
	

	
	

	

测试:

    @Test
    public void getEmpById() {
        Emp emp = empMapper.getEmpById2(2);
        System.out.println(emp);
        // Emp{empId=2, empName='李四', age=22, gender='女', deptId=2}
    }

2、多对一映射处理

场景模拟: 查询员工信息以及员工所对应的部门信息

处理多对一的映射关系:

        1、级联方式处理映射关系

        2、使用association处理映射关系

        3、分布查询方式处理映射关系

准备:

修改 emp 实体类:

package com.chenyixin.ssm.pojo;

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

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

2.1、级联方式处理映射关系

EmpMapper 接口:

    /**
     * 根据 empId 获取 emp 的所有信息(包括该员工的部门信息)
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);

EmpMapper.xml 配置文件:

	
		
		
		
		
		
		
	

	
	
	

测试:

    @Test
    public void getEmpAndDeptByEmpId() {
        Emp emp = empMapper.getEmpAndDeptByEmpId(1);
        System.out.println(emp);
        // Emp{empId=1, empName='张三', age=20, gender='女', dept=Dept{deptId=1, deptName='A'}}
    }

2.2、使用association处理映射关系

association:处理多对一的映射关系(处理实体类类型的属性)

        property:设置需要处理映射关系的属性的属性名

        javaType:设置要处理的属性的类型

        注意:一对一的映射关系可以用多对一的方式去处理

EmpMapper 接口:

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

EmpMapper.xml 配置文件:

	
		
		
		
		
		
			
			
		
	

	
	

测试:

    @Test
    public void getEmpAndDeptByEmpId2() {
        Emp emp = empMapper.getEmpAndDeptByEmpId2(3);
        System.out.println(emp);
        // Emp{empId=3, empName='王五', age=21, gender='男', dept=Dept{deptId=3, deptName='C'}}
    }

2.3、分步查询处理映射关系

association:处理多对一的映射关系(处理实体类类型的属性)

        property:设置需要处理映射关系的属性的属性名

        javaType:设置要处理的属性的类型

        select : 设置分布查询的 sql 的唯一标识(namespace.id)

        column:将查询出的某个字段作为分布查询的 sql 条件        

EmpMapper 接口:

    /**
     * 分布查询:根据员工 id 查询对应员工信息 及其 该员工所对应的部门信息 (第二步)
     * @param deptId
     * @return
     */
    Dept getEmpAndDeptByStopTwo(@Param("deptId") Integer deptId);

DeptMapper 接口:

    /**
     * 分布查询:根据员工 id 查询对应员工信息 及其 该员工所对应的部门信息 (第一步)
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByStopOne(@Param("empId") Integer empId);

DeptMapper.xml 配置文件:


	
	

EmpMapper.xml 配置文件:

	
		
		
		
		
		
	

	
	

测试:(记得开启全局配置

@Test
public void getEmpAndDeptByStopOne() {
    Emp emp = empMapper.getEmpAndDeptByStopOne(4);
    System.out.println(emp);
}

结果:(查询了两次)

Java框架 MyBatis自定义映射resultMap_第1张图片

2.4、延迟加载

概念:对于实体类关联的属性到需要使用时才查询。也叫懒加载。

在全局变量中设置延迟加载:

	
		
		

		
		
		

		
		
	

测试1:(以在全局设置中开启了延迟加载)

    @Test
    public void getEmpAndDeptByStopOne() {
        Emp emp = empMapper.getEmpAndDeptByStopOne(4);
        System.out.println(emp.getEmpName());
    }

结果:

因为全局变量会对所有的分布查询开启延迟加载,但也可以在 Mapper配置文件中的resultMap 设置延迟加载。

association:       

          fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载

                 fetchType=“eager(立即加载) | lazy(延迟加载)”

	
		
		
		
		
		
	

测试2:(测试代码与测试1相同)(以在全局设置中开启了延迟加载,但也在Mapper配置文件中的resultMap 设置了延迟加载)

结果:

Java框架 MyBatis自定义映射resultMap_第2张图片

3、一对多映射处理

场景模拟: 查询部门信息 及 在其部门中的员工信息

处理一对多的映射关系

        1、collection

        2、分布查询

准备:

修改 dept 实体类:


public class Dept {
    private Integer deptId;
    private String deptName;
    private List emps;

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

    public Dept() {
    }

    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 + '\'' +
                ", emps=" + emps +
                '}';
    }
}

3.1、collection

collection (其子标签与 association 子标签用法相同)

        collection:处理一对多的映射关系(处理集合类型的属性)

        ofType:设置集合类型的属性中存储的数据的类型

DeptMapper 接口:

    /**
     * 根据部门 id 查询部门以及部门中的员工信息
     * @param deptId
     * @return
     */
    Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);

DeptMapper.xml 配置文件:


		
		
		
			
			
			
			
		
	
	
	
	

测试:

public class DeptMapperTest {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);

    @Test
    public void getDeptAndEmpByDeptId() {
        Dept dept = deptMapper.getDeptAndEmpByDeptId(1);
        System.out.println(dept);
        // Dept{deptId=1, deptName='A', 
        // emps=[Emp{empId=1, empName='张三', age=20, gender='女', dept=null}, 
        //       Emp{empId=4, empName='赵六', age=23, gender='男', dept=null}]}
    }
}

3.2、分步查询

DeptMapper 接口:

    /**
     * 通过分布查询 查询部门以及部门中的员工信息的第一步
     * @param deptId
     * @return
     */
    Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);

EmpMapper 接口:

    /**
     * 通过分布查询 查询部门以及部门中的员工信息的第二步
     * @param deptId
     * @return
     */
    Emp getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);

EmpMapper.xml 配置文件:

	
	

DeptMapper.xml 配置文件:

	
		
		
		
	
	
	

测试:

    @Test
    public void getDeptAndEmpByStepOne() {
        Dept dept = deptMapper.getDeptAndEmpByStepOne(3);
        System.out.println(dept);
    }

结果:

Java框架 MyBatis自定义映射resultMap_第3张图片

4、总结

字段名和属性名不一致的情况,如何处理映射关系:
   1、为查询的字段设置别名,和属性名一致

   2、当字段符合 MySql 的要求使用,而属性符合 java 的要求使用驼峰,
           此时可以在 MyBatis 的核心文件中使用 setting 标签设置一个全局变量配置,
           可以自动将下划线映射为驼峰
           如:emp_id -> empId

   3、使用 resultMap 自定义映射处理
      resultMap:设置自定义的映射关系
      id:唯一表示
      type:处理映射关系的实体类的类型

      常用标签
         id: 处理主键和实体类中属性的映射关系
         result:处理普通字段和实体类中属性的映射关系
         column:设置映射关系中的字段名,必须是sql 查询出的某个字段
         property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名

映射关系处理:

使用 resultMap 自定义映射处理

        处理多对一的映射关系:

                1、级联方式处理映射关系

                2、使用 association 处理映射关系

                3、分布查询方式处理映射关系

        处理一对多的映射关系

                1、collection

                2、分布查询

resultMap:设置自定义的映射关系
        id:唯一表示
        type:处理映射关系的实体类的类型

常用标签
   id: 处理主键和实体类中属性的映射关系
   result:处理普通字段和实体类中属性的映射关系
   column:设置映射关系中的字段名,必须是sql 查询出的某个字段
   property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名

   association:处理多对一的映射关系(处理实体类类型的属性)
      property:设置需要处理映射关系的属性的属性名
      javaType:设置要处理的属性的类型
      select : 设置分布查询的 sql 的唯一标识(namespace.id)
      column:将查询出的某个字段作为分布查询的 sql 条件
      fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载
      fetchType=“eager(立即加载) | lazy(延迟加载)”

         注意:一对一的映射关系可以用多对一的方式去处理
   
     collection:处理一对多的映射关系(处理集合类型的属性)
          property:设置需要处理映射关系的属性的属性名
          ofType:设置集合类型的属性中存储的数据的类型
          select : 设置分布查询的 sql 的唯一标识(namespace.id)
          column:将查询出的某个字段作为分布查询的 sql 条件
          fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载
         fetchType=“eager(立即加载) | lazy(延迟加载)”

      注意:多对多的映射关系可以用一对多的方式去处理

全局变量的设置:

	
		
		

		
		
		

		
		
	

你可能感兴趣的:(Java,#,Java框架,mybatis,java,开发语言)