Mybatis学习笔记——select相关知识(返回集合类型、自定义映射[联合查询|分步查询|集合属性封装|鉴别器])

返回List

编写接口方法

public List<Employee> getEmpsByLastNameLike(String lastName);

编写sql语句

 <!-- public List<Employee> getEmpsByLastNameLike(String lastName); -->
 <!-- resultType, 如果要返回的是一个集合,要写集合中的元素类型-->
  <select id="getEmpsByLastNameLike" resultType="com.shen.mybaties.bean.Employee" >
    select * from tbl_employee where last_name like #{lastName}
  </select>

注意:虽然是List集合,但是resultType还是要写集合元素的类型,MyBatis会自动帮我们把结果集封装成指定元素的集合类型。


返回Map

单条记录的Map

编写接口方法

    //返回一个记录的map,key就是列明,值就是对应的值
    public Map<String,Object> getEmpByIdReturnMap(Integer id);

编写sql语句

  <!-- public Map<String,Object> getEmpByIdReturnMap(Integer id); -->
  <select id="getEmpByIdReturnMap" resultType="map">
    select * from tbl_employee where id = #{id}
  </select>

注意:这里的resultType="map",MyBatis给Map起了别名就是map,返回的记录就会以Map的形式返回。

多条记录的Map

编写接口方法

    //多条记录封装一个map,Map<Integer(指定类型),Employee>:键是记录的某个属性,值是记录封装后的JavaBean
    //告诉MyBatis封装这个map的时候,使用哪个属性作为map的key
    @MapKey("lastName")
    public Map<String,Employee> getEmpsByLastNameReturnMap(String lastName);

注意:这里的Map,Key是指定的bean的某属性值,Value是记录封装的bean对象。
指定Key需要使用@MapKey这个注解,它的value是bean对象的属性名称。

编写sql语句

  <!-- public Map<Integer,Employee> getEmpsByLastNameReturnMap(String lastName); -->
  <select id="getEmpsByLastNameReturnMap" resultType="com.shen.mybaties.bean.Employee">
    select * from tbl_employee where last_name like #{lastName}
  </select>

这里的resultType依旧是Map中Value元素的类型。


自定义映射规则(<resultMap>)

常规写法

编写接口方法

    public Employee getEmpById(Integer id);

编写映射规则

    <!-- 自定义某个javaBean的封装规则
        type:自定义规则的Java类型
        id:唯一id方便引用
    -->
    <resultMap type="com.shen.mybaties.bean.Employee" id="MyEmp">
        <!-- 指定主键列的封装规则
            id定义主键会底层有优化 
            column:指定哪一列
            property:指定对应的javaBean属性
        -->
        <id column="id" property="id"/>
        <!-- 定义普通列封装规则 -->
        <result column="Last_name" property="lastName"/>
        <!-- 其他不指定的列会自动封装,推荐:只要写resultMap,就要把全部的映射规则都写上-->
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    </resultMap>

这个是重点,即编写我们自己定制的映射规则。
(0)属性id:唯一id,用于引用,下面sql语句的resultMap用这个id进行引用。
(1)子标签<id>:定义主键的映射规则,相比<result>,会有底层的优化。
(2)子标签<result>:定义普通列的映射规则
(3)(1)和(2)的子标签<column>:结果集的列名,和下面一一对应
(4)(1)和(2)的子标签<property>:javaBean的属性名,和上面一一对应
注意:若没有指定,则自动进行封装(找对应列名封装)。

编写sql语句

    <!-- resultMap:自定义结果集映射规则 ,resultMap和resultType只能存在一个 -->
    <!-- public Employee getEmpById(Integer id); -->
    <select id="getEmpById" resultMap="MyEmp">
        select * from tbl_employee where id = #{id}
    </select>

联合查询

增加bean

public class Department {

    private Integer id;
    private String departmentName;

    public Department() {
        super();
    }

    public Department(Integer id, String departmentName) {
        super();
        this.id = id;
        this.departmentName = departmentName;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    @Override
    public String toString() {
        return "Department [id=" + id + ", departmentName=" + departmentName + "]";
    }

}

增加成员变量。

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
    private Department dept;

每个员工都有一个部门信息。

利用级联属性

编写接口方法
    public Employee getEmpAndDept(Integer id);
编写映射规则
    <!-- 
        联合查询:级联属性封装结果集
    -->
    <resultMap type="com.shen.mybaties.bean.Employee" id="MyDifEmp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="did" property="dept.id"/>
        <result column="dept_name" property="dept.departmentName"/>
    </resultMap>

这是重点:其中的did和dept_name都是部门信息,后面的property使用级联属性封装结果集,使用dept.id和dept.departmentName

编写sql语句
    <!-- public Employee getEmpAndDept(Integer id); -->
    <select id="getEmpAndDept" resultMap="MyDifEmp">
        select e.id id,e.last_name last_name, e.gender gender, e.d_id d_id,
        d.id did, d.dept_name dept_name
        from tbl_employee e, tbl_dept d 
        where e.d_id=d.id and e.id=#{id}
    </select>

这里的resultMap引用的就是刚才的id,这里select出来的结果集列就用到了自定义的映射规则。

利用association标签

自定义的映射规则
    <!-- 使用association定义关联的单个对象的封装规则 -->
    <resultMap type="com.shen.mybaties.bean.Employee" id="MyDifEmp2">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <!-- association可以指定联合的javaBean对象 
            property="dept" 指定哪个属性是联合的对象
            javaType: 指定这个属性对象的类型 (不能省略)
        -->
        <association property="dept" javaType="com.shen.mybaties.bean.Department">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
        </association>
    </resultMap>

这里使用association标签进行联合对象的属性映射。


分步查询

利用association标签

编写自定义的映射规则
    <!-- 使用association进行分步查询:
            1.按照员工ID查询id信息
            2.根据查询员工信息中的d_id值去部门表查出部门信息
            3.部门设置到员工信息中

            流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的类型
    -->
    <resultMap type="com.shen.mybaties.bean.Employee" id="MyEmpByStep">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!-- association定义关联对象的封装规则 
            select:表明当前属性是调用select指定的方法查出的结果
            column:指定将哪一列的值传给这个方法
        -->
        <association property="dept" 
            select="com.shen.mybaties.dao.DepartmentMapper.getDeptById"
            column="d_id">
        </association>
    </resultMap>

重点<association>中需要配置几个属性。
(1)select:表明当前属性是调用select指定的方法查出的结果,这里需要用到其他的select方法,我们需要编写对应的Mapper接口和Mapper XML文件。
(2)column:指定将哪一列的值传递给这个select方法(猜测只能传一个)。

编写Mapper接口和Mapper XML

Department属性的Mapper接口:

public interface DepartmentMapper {

    public Department getDeptById(Integer id);
}

DepartmentMapper接口对应的xml文件:

<?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="com.shen.mybaties.dao.DepartmentMapper">

    <!-- public Department getDeptById(Integer id); -->
    <select id="getDeptById" resultType="com.shen.mybaties.bean.Department">
        select id,dept_name departmentName from tbl_dept where id = #{id};
    </select>

</mapper>

可以看出:这个查询方法需要一个参数id,而在<assiciation>中的column中指定一个参数传进来,这个参数是上层结果集的某列。
EmployeeMapper的XML文件:

    <!-- public Employee getEmpByIdStep(Integer id); -->
    <select id="getEmpByIdStep" resultMap="MyEmpByStep">
        select * from tbl_employee where id = #{id}
    </select>
测试

这里写图片描述
这里看到:
(1)先进行员工信息的查询
(2)利用员工信息的某列,根据这列去查询部门信息
(3)再将部门信息整合到员工信息中。

延迟加载

在使用分布查询的基础上,我们可以简单的通过两个设置,来达到延迟加载的效果(懒加载)。
全局配置文件中加入如下两个设置:

    <settings>
        <!-- 其他配置 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

这样就可以达到延迟加载的效果,即用到才去查询。
这里写图片描述

注意点<association>只能是单个的联合对象,而不能去加载一个对象的集合。


集合类型的属性封装

场景:查询部门的时候将部门对应的所有员工信息也查询出来。

public class Department {

    private Integer id;
    private String departmentName;
    private List<Employee> emps;
}

collection嵌套结果集的方式

编写映射规则
    <!-- 
        collection嵌套结果集的方式,定义关联的集合类型的属性封装规则
    -->
    <resultMap type="com.shen.mybaties.bean.Department" id="MyDept">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
        <!-- 
            collection定义关联集合类型的属性的封装规则 
            ofType:指定集合里面元素的类型
        -->
        <collection property="emps" ofType="com.shen.mybaties.bean.Employee">
            <!-- 定义这个集合的封装规则 -->
            <id column="eid" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>

重点:由于Department的emps属性为一个集合,所以封装的时候,要使用<collection>标签来封装。
其中两个属性:
(1)property:表明是上层对象的哪一个属性名。
(2)ofType:表明集合内部的元素类型。(不要想当然,不是JavaType

sql语句
    <!-- public Department getDeptByIdPlus(Integer id); -->
    <select id="getDeptByIdPlus" resultMap="MyDept">
        SELECT d.id did,d.dept_name dept_name,
                e.id eid,e.last_name last_name,
                e.email email,e.gender gender
        FROM tbl_dept d
        LEFT JOIN tbl_employee e
        ON d.id=e.d_id
        WHERE d.id = #{id}
    </select>

这里我们使用连接查询(效果一样)。

collection分步查询的方式

编写映射规则以及sql语句
    <resultMap type="com.shen.mybaties.bean.Department" id="MyDeptStep">
        <id column="id" property="id"/>
        <result column="dept_name" property="departmentName"/>
        <collection property="emps" 
            select="com.shen.mybaties.dao.EmployeeMapperPlus.getEmpsByDeptId" 
            column="id"></collection>
    </resultMap>
    <!-- public Department getDeptByIdStep(Integer id); -->
    <select id="getDeptByIdStep" resultMap="MyDeptStep">
        select id,dept_name from tbl_dept where id = #{id}
    </select>

就像单元素的分步查询一样,但这里使用的是collection而不是association,它内部也有一个select属性和column属性,同样select负责第二步的查询语句,column负责传入select需要的参数。

编写第二步查询的Mapper接口方法和Mapper XML
    public List<Employee> getEmpsByDeptId(Integer deptId);
    <!-- public List<Employee> getEmpsByDeptId(Integer deptId); -->
    <select id="getEmpsByDeptId" resultType="com.shen.mybaties.bean.Employee">
        select * from tbl_employee where d_id=#{deptId}
    </select>

上面两个是为了部门查询时,第二步查询员工信息的查询语句。

分步查询的补充

传递多值

不管是单元素(association)还是集合类型(collection),进行后面步骤查询的时候,都需要一个select属性,这里面规定一个外部的查询引用(namespace+select id),通常他都需要参数才能进行查询(#{XX}),同时有一个column属性,是为了传入select需要的参数,column是上层查询的结果集的列名
解决办法:将多列的值封装map传递 ,column="{key1=column1,key2=column2}"

局部延迟加载配置

<association><collection>都有一个属性叫fetchType,默认为lazy。
虽然在全局配置中,我们开启了延迟加载,但是可以在局部进行配置,仅对当前的封装生效。
fetchType有lazyeager两个值,字面意思。

discriminator鉴别器

mybits可以使用discriminator判断某列的值,然后根据某列的值改变封装行为。

编写带有鉴别器的映射规则

规则:
如果查出的是女生,就把部门信息查询出来,否则不查询。
如果是男生,把last_name这一列的值赋值给email。

    <!--  鉴别器:
        mybits可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
        封装Employee:
            如果查出的是女生,就把部门信息查询出来,否则不查询
            如果是男生,把last_name这一列的值赋值给email   
    -->
    <resultMap type="com.shen.mybaties.bean.Employee" id="MyEmpDis">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!-- 
            column:指定判定的列名 
            javaType:列值对应的java类型
        -->
        <discriminator javaType="string" column="gender">
            <!-- 女生 resultType:指定封装的结果类型;不能缺少resultType或resultMap-->
            <case value="0" resultType="com.shen.mybaties.bean.Employee">
                 <association property="dept" 
                    select="com.shen.mybaties.dao.DepartmentMapper.getDeptById"
                    column="d_id">
                </association>
            </case>
            <!-- 男生 -->
            <case value="1" resultType="com.shen.mybaties.bean.Employee">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="last_name" property="email"/>
                <result column="gender" property="gender"/>
            </case>
        </discriminator>
    </resultMap>
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值