MyBatis---查询

方法返回List集合

在这里插入图片描述

  • 实际开发中在定义查询方法的时候,往往会将多个数据包装到一个List集合中返回,MyBatis也支持这样的操作.
  • 示例:定义接口方法
    public List<Employee> getAll(@Param("column") String column);
  • 配置sql映射文件
  • 此时resultType属性的类型,应该是Lis<Employee>集合中的类型,也就是Employee类型

    <select id="getAll" resultType="mao.shu.vo.Employee">
        SELECT *
        FROM employee
        ORDER BY ${column}
    </select>
  • 测试方法
    @Test
    public void getAll(){
        EmployeeDAO employeeDAO = this.sqlSession.getMapper(EmployeeDAO.class);
        List<Employee> emp = employeeDAO.getAll("id");
        for (Employee vo : emp){
            System.out.println(vo);
        }
    }

在这里插入图片描述

返回Map

  • 在实际开发中,有些时候会将查询方法返回一个Map集合,如果使用MyBatis实现,则MyBatis会自动对查询结果进行处理.
  • 返回一条数据
  • 如果查询结果返回的只是一条数据,那么返回的Map集合中,key=字段名称,value=字段对应的内容.
  • 示例:查询以下的数据

在这里插入图片描述

  • 定义接口的查询方法
public Map<String,Object> getEmp(Integer id);
  • 定义sql映射文件
  • sql语句的resultType 属性值为 Map类型的别名"map"
    <select id="getEmp" resultType="map">
        SELECT id, ename, age, job
        FROM employee
        WHERE id = #{id}
    </select>
  • 测试方法
    @Test
    public void getEmp(){
        EmployeeDAO employeeDAO = this.sqlSession.getMapper(EmployeeDAO.class);
        Map<String,Object> emp = employeeDAO.getEmp(1);
        System.out.println(emp);
    }

在这里插入图片描述

  • 返回多条数据
  • 如果返回多条数据,则可以使用 @MapKey 注解来指定使用哪个属性用于做Map集合的key,MyBatis会自动将多条数据解析为实体类对象作为Map集合的value
  • 示例:查询以下数据

在这里插入图片描述

  • 定义接口方法
@MapKey("id")
public Map<Integer,Employee> getEmpsByName(String name);
  • 定义sql映射文件
<select id="getEmpsByName" resultType="map">
        SELECT id, ename, age, job
        FROM employee
        WHERE ename = #{ename}
    </select>
  • 测试方法
    @Test
    public void getEmpsByName(){
        EmployeeDAO employeeDAO = this.sqlSession.getMapper(EmployeeDAO.class);
        Map<Integer,Employee> emp = employeeDAO.getEmpsByName("添加测试");
        System.out.println(emp);
    }

在这里插入图片描述

自定义结果映射规则

  • 当有些特殊的字段于类属性名称相差太大时,可以通过使用<resultMap>标签自定义转换规则

在这里插入图片描述

  • 示例:自定义数据表字段于类属性转换规则
  • 使用<resultMap>标签设置转换规则
  • 在<select>sql映射标签中使用 resultMap属性指定使用的转换规则
<?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="mao.shu.dao.EmployeeDAOPlus">
    <!--配置数据表Employee表的字段与Employee类属性之间的转换规则
        <id> 标签作为数据表的主键,为特殊字段,
        column指定数据表对应的列名称
        property指定java类对应的属性名称
        
        <result>标签描述普通的字段与属性
    -->
    <resultMap id="employeeToEmp" type="mao.shu.vo.Employee">
        <id column="id" property="id"/>
        <result column="ename" property="ename"/>
        <result column="age" property="age"/>
        <result column="job" property="job"/>
    </resultMap>

    <!--sql语句中使用 resultMap 属性指定自定义的转换类型-->
    <select id="getOneEmp" resultMap="employeeToEmp">
        SELECT id, ename, age, job
        FROM employee
        WHERE id = #{id}
    </select>
</mapper>
  • 测试规则

public class EmployeeDAOPlusTest {
    private SqlSession sqlSession;
    @Before
    public void before() throws IOException {
        String resource = "config/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSession = sqlSessionFactory.openSession();
    }
    @After
    public void after(){
        this.sqlSession.commit();
        this.sqlSession.close();
    }
    @Test
    public void getOneEmp(){
        EmployeeDAOPlus employeeDAOPlus = this.sqlSession.getMapper(EmployeeDAOPlus.class);
        Employee employee = employeeDAOPlus.getOneEmp(1);
        System.out.println(employee);
    }

}

在这里插入图片描述

关联查询

  • 数据库中有两张表,雇员表和部门表,这两张表为单向一对第一关系
  1. Employee(描述雇员)

在这里插入图片描述

  1. Department(描述部门)

在这里插入图片描述

  • 每一个雇员表中包含一个dept_id字段,对应Department部门表的id

在这里插入图片描述

  • Employee数据表的实体类
public class Employee {
    private Integer id;
    private String ename;
    private Integer age;
    private String job;
    private Department department;
    ```
}
  • Department数据表的实体类

public class Department {
    private Integer deptID;
    private String dname;
    ...
}

级联查询结果封装

在这里插入图片描述

  • 定义接口查询方法
public Employee getEmpAndDepartment(Integer id);
  • 定义sql映射文件
    <resultMap id="empAndDept" type="mao.shu.vo.Employee">
        <id column="id" property="id"/>
        <result column="ename" property="ename"/>
        <result column="age" property="age"/>
        <result column="job" property="job"/>
        <result column="deptno" property="department.deptID"/>
        <result column="dname" property="department.dname"/>
    </resultMap>
    <select id="getEmpAndDepartment" resultMap="empAndDept">
        SELECT e.id id, e.ename ename, e.age age, e.job job, e.dept_id deptid, d.dept_id deptno, d.dname dname
        FROM employee e,
             department d
        WHERE e.dept_id = d.dept_id
          AND e.id = #{id}

    </select>
  • 测试程序
    @Test
    public void getEmpAndDepartment(){
        EmployeeDAOPlus employeeDAOPlus = this.sqlSession.getMapper(EmployeeDAOPlus.class);
        Employee employee = employeeDAOPlus.getEmpAndDepartment(1);
        System.out.println(employee);
    }
  • 测试结果

在这里插入图片描述

association定义关联对象封装规则

  • 示例:修改sql映射文件
 <resultMap id="empAndDept" type="mao.shu.vo.Employee">
        <id column="id" property="id"/>
        <result column="ename" property="ename"/>
        <result column="age" property="age"/>
        <result column="job" property="job"/>
        <!--<result column="deptno" property="department.deptID"/>
        <result column="dname" property="department.dname"/>-->
        
        <!--使用association描述关联对象
            javaType为对应的java类名称,该属性必须要指定
        -->
        <association property="department" javaType="mao.shu.vo.Department">
            <id column="deptno" property="deptID"/>
            <result column="dname" property="dname"/>
        </association>
    </resultMap>
    <select id="getEmpAndDepartment" resultMap="empAndDept">
        SELECT e.id id, e.ename ename, e.age age, e.job job, e.dept_id deptid, d.dept_id deptno, d.dname dname
        FROM employee e,
             department d
        WHERE e.dept_id = d.dept_id
          AND e.id = #{id}

    </select>
  • 测试代码
    @Test
    public void getEmpAndDepartment(){
        EmployeeDAOPlus employeeDAOPlus = this.sqlSession.getMapper(EmployeeDAOPlus.class);
        Employee employee = employeeDAOPlus.getEmpAndDepartment(1);
        System.out.println(employee);
    }

在这里插入图片描述

association分步查询

  • 对于每一个数据表都有对应的一个操作接口,当要使用关联查询的时候,可以通过<association>调用其他sql语句来为关联对象赋值.

  • 使用association指定关联属性使用的查询方法:

    • property:指定关联属性名称
    • select:指定调用的方法为关联属性赋值,select值为 方法sql映射文件的 namespace+对应<select>的id值
    • column:将查询出的哪一列数据传递给调用的方法
  • 例如:雇员类中拥有一个部门对象,当查询一个雇员信息的时候,希望将部门信息一起查出来,并赋值给部门对象.

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 部门接口操作方法
public Department getDeptById(Integer id);
  • getDeptById()方法的sql映射文件
<mapper namespace="mao.shu.dao.DepartmentDAO">
   <select id="getDeptById" resultType="mao.shu.vo.Department">
       SELECT d.dept_id, dname
       FROM department d
      WHERE dept_id = #{id}
   </select>
</mapper>
  • 雇员操作接口方法
public Employee getEmpStep(Integer id);
  • getEmpStep()方法的sql映射文件
   <select id="getEmpStep" resultMap="getEmpStepResultMap">
        SELECT id, ename, age, job, dept_id
        FROM employee
        WHERE id = #{id}
    </select>
    
    <resultMap id="getEmpStepResultMap" type="mao.shu.vo.Employee">
        <id column="id" property="id"/>
        <result column="ename" property="ename"/>
        <result column="age" property="age"/>
        <result column="job" property="job"/>
        <!--使用association指定关联属性的封装规则
            property:指定关联属性名称
            select:指定调用的方法为关联属性赋值,select值为 方法sql映射文件的 namespace+对应<select>的id值            
            column:将查询出的哪一列数据传递给调用的方法
        -->
        <association
                property="department"
                select="mao.shu.dao.DepartmentDAO.getDeptById"
                column="dept_id">
        </association>
    </resultMap>
  • 测试方法
    @Test
    public void getEmpStep(){
        EmployeeDAOPlus employeeDAOPlus = this.sqlSession.getMapper(EmployeeDAOPlus.class);
        Employee employee = employeeDAOPlus.getEmpStep(1);
        System.out.println(employee);
    }

在这里插入图片描述

懒加载

  • 当进行查询时,默认情况下会对关联属性一起进行查询,也就是说尽管没有用到关联属性,MyBatis也会默认去调用关联属性的方法,导致过多的方法问数据库,导致性能下降.

在这里插入图片描述

  • 示例:开启懒加载
  • 修改MyBatis配置文件
    <settings>
        <!--开启懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

在这里插入图片描述

定义关联集合封装规则

  • 当实体类中拥有一个集合的关联属性,在编写映射sql语句时,可以使用"<collection> 标签来处理集合属性封装规则.

在这里插入图片描述

  • 示例:一个部门中会包含多个雇员,在部门的实体类中,可以使用List集合来描述多个雇员信息

在这里插入图片描述

  • 定义接口查询方法,根据一个部门id查询一个部门信息,并且将部门中所有的雇员信息一起查出来
public Department getDeptAndEmpsById(Integer id);
  • 配置sql映射文件
  <select id="getDeptAndEmpsById" resultMap="getDeptAndEmpsById_resultMap">
        SELECT dept.dept_id deptId, dept.dname, emp.id empId, emp.ename, emp.age, emp.job, emp.dept_id
        FROM department dept
                 LEFT JOIN employee emp
                           ON dept.dept_id = emp.dept_id
        WHERE dept.dept_id = #{id}
    </select>

    <resultMap id="getDeptAndEmpsById_resultMap" type="mao.shu.vo.Department">
        <id column="deptId" property="deptId"/>
        <result column="dname" property="dname"/>

        <!--使用collection定义集合的封装规则
            property:描述实体类中集合的名字
            ofType:描述集合中元素的类型
        -->
        <collection property="emps" ofType="mao.shu.vo.Employee">
            <id column="empId" property="id"/>
            <result column="ename" property="ename"/>
            <result column="age" property="age"/>
            <result column="job" property="job"/>
        </collection>
    </resultMap>
  • 测试方法
    @Test
    public void getDeptAndEmpsById(){
        DepartmentDAO departmentDAO = this.sqlSession.getMapper(DepartmentDAO.class);
        Department department = departmentDAO.getDeptAndEmpsById(1);
        System.out.println(department);
        List<Employee> emps = department.getEmps();
        for (Employee emp : emps){
            System.out.println(emp);
        }
    }

在这里插入图片描述

collection分步查询$延迟加载

  • 分布查询:
    1. 先查询出部门信息
    2. 在查询出部门中所有的员工信息
  • 在这里插入图片描述
  • 示例:在雇员接口上添加根据部门id查询所有的雇员的方法
public List<Employee> getEmpsByDeptId(Integer deptId);
  • 在sql映射文件中添加对应的sql查询语句
<select id="getEmpsByDeptId" resultType="mao.shu.vo.Employee">
        SELECT id,ename,age,job,dept_id
        FROM employee
        WHERE dept_id = #{id}
    </select>
  • 在部门接口中添加分布查询的方法
    public Department getDeptAndEmpsByIdStep(Integer id);
  • 修改部门的sql映射文件,调价对应的sql映射语句
    <select id="getDeptAndEmpsByIdStep" resultMap="getDeptAndEmpsByIdStep_resultMap">
        SELECT dept_id, dname
        FROM department
        WHERE dept_id = #{id}
    </select>
    <resultMap id="getDeptAndEmpsByIdStep_resultMap" type="mao.shu.vo.Department">
        <id column="dept_id" property="deptID"/>
        <result column="dname" property="dname"/>
        <!--
            分步查询:
            使用select指定要使用的查询方法
            column:指定要将那列数据传给调用的方法
        -->
        <collection property="emps" select="mao.shu.dao.EmployeeDAOPlus.getEmpsByDeptId" column="dept_id"/>
    </resultMap>
  • 测试方法
    @Test
    public void getDeptAndEmpsByIdStep(){
        DepartmentDAO departmentDAO = this.sqlSession.getMapper(DepartmentDAO.class);
        Department department = departmentDAO.getDeptAndEmpsByIdStep(1);
        System.out.println(department);
        List<Employee> emps = department.getEmps();
        for (Employee emp : emps){
            System.out.println(emp);
        }
    }

在这里插入图片描述

分布查询传递多列值

在这里插入图片描述

  • 示例:传递多个列值
    <resultMap id="getDeptAndEmpsByIdStep_resultMap" type="mao.shu.vo.Department">
        <id column="dept_id" property="deptID"/>
        <result column="dname" property="dname"/>
        <!--
        column:可以同时传递多个列值
        格式为:{关键字=列名称,关键字=列名称...} 
        -->
        <collection column="{id=dept_id,dn=dname}" property="emps" select="mao.shu.dao.EmployeeDAOPlus.getEmpsByDeptId" />
    </resultMap>
  • 接收列值
  • 接收时使用"#{关键字}"即可接收对应的列值
 <select id="getEmpsByDeptId" resultType="mao.shu.vo.Employee">
        SELECT id,ename,age,job,dept_id
        FROM employee
        WHERE dept_id = #{id}
    </select>
  • 示例:覆盖全局设置的懒加载策略
  • 在<association>标签或者<collection>标签中都可以定义对关联属性的懒加载策略
    • 使用 fetchType 属性控制懒加载策略
      • lazy:使用懒加载
      • eager:不使用懒加载,对于关联属性立即加载
<resultMap id="getDeptAndEmpsByIdStep_resultMap" type="mao.shu.vo.Department">
        <id column="dept_id" property="deptID"/>
        <result column="dname" property="dname"/>
        <!--
            分步查询:
            使用select指定要使用的查询方法
            column:指定要将那列数据传给调用的方法
        -->
        <!--
        column:可以同时传递多个列值
        格式为:{关键字=列名称,关键字=列名称...}
        -->
        <!--
            在<association>标签或者<collection>标签中都可以定义对关联属性的懒加载策略
            使用 fetchType 属性控制懒加载策略
            lazy:使用懒加载
            eager:不使用懒加载,对于关联属性立即加载
        -->
        <collection fetchType="eager" column="{id=dept_id,dn=dname}" property="emps" select="mao.shu.dao.EmployeeDAOPlus.getEmpsByDeptId" />
    </resultMap>
    

在这里插入图片描述

discrimination鉴别器

  • MyBatis允许在为结果进行封装的时候,使用鉴别器来判断某列的值,根据不同的值来对结果进行不同的封装

  • 示例:对查询雇员的结果中, 如果ename为"测试人员",则将job属性设置为ename字段值

    <resultMap id="empAndDept" type="mao.shu.vo.Employee">
        <id column="id" property="id"/>
        <result column="ename" property="ename"/>
        <result column="age" property="age"/>
        <result column="job" property="job"/>
        <!--<result column="deptno" property="department.deptID"/>
        <result column="dname" property="department.dname"/>-->

        <!--使用association描述关联对象
            javaType为对应的java类名称,该属性必须要指定
        -->


        <association property="department" javaType="mao.shu.vo.Department">
            <id column="deptno" property="deptID"/>
            <result column="dname" property="dname"/>
        </association>

        <!--辨别器
            如果ename为"测试人员",则将job属性设置为ename字段值
            javaType:字段对应的java类型
            column:判断的数据列
            <case value="测试数据">:判断对应的数据列值是否为value值
            如果是,则以\<case\>标签中的封装规则为结果进行封装
        -->
       <discriminator javaType="string" column="ename">
            <case value="测试数据" resultType="mao.shu.vo.Employee">
                <id column="id" property="id"/>
                <result column="ename" property="job"/>

            </case>
        </discriminator>
    </resultMap>

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43386754/article/details/88603286