Mybatis的查询、关联查询

使用Mybatis进行查询

查询结果的映射

Mybatis通过<select>进行查询。通过<resultMap>将查询结果封装成实体类:

<resultMap id="deptMap" type="Dept">
    <!--<![CDATA[<id>是主键标签]]> -->
    <!--<![CDATA[<property是类中的属性名,column是sql语句中查询出来的字段>]]> -->
    <id property="id" column="ID"/>
    <!--<![CDATA[<result>是主键标签]]> -->
    <result property="name" column="NAME"/>
</resultMap>

<select id="getAllDept" resultMap="deptMap">
    select ID,NAME from DEPT
</select>

<resultMap>用于封装结果集。一个Mapper中可以有多个<resultMap>,每个<resultMap>的id是唯一的。type用于指定结果集对应的实体类类型。type="Dept"即将<resultMap>中所有的属性都对应到Dept类中。

对应关系如下图所示:
在这里插入图片描述
我们可以这样理解,一个查询语句,从查询出结果,到封装成实体类,经历如下步骤:

\1. 当使用<select>查询出结果后,会根据<select>中resultMap=”deptMap”找到id=”deptMap”的<resultMap>标签

\2. 根据<resultMap>的type=”Dept”找到Dept对应的类,这里Dept是别名,也可以写成全路径pojo.Dept。

\3. <resultMap>中的<result>标签,将查询结果中的字段与实体类中的属性对应起来,property=”name”是找到Dept类中的name属性,column=”NAME”中NAME是SQL语句中NAME字段对应的值,通过setName方法将结果集绑定到name属性上。

需要注意的是column=”NAME”中的NAME不是数据库中的字段名,而是select语句中查询出来的字段别名,因为我们可以用as去给字段起别名。如上面改变上面的语句,为查询结果起别名,对应的column也要改变:
在这里插入图片描述
测试代码:

@Test
public void testSelectAll() {
    //当查询结果有多个的时候,使用selectList
    List<Dept> deptList = session.selectList("DEPT.getAllDept");
    for (Dept dept : deptList) {
        System.out.println(dept.getName());
    }
}

session.selectList适用于查询结果是一个集合的情况,如果实现按主键查询,则使用session.selectOne方法。如按主键查询:

<select id="getDeptById" parameterType="int" resultMap="deptMap">
    select ID,NAME from DEPT where ID=#{id}
</select>

测试代码:

@Test
public void testSelectOne() {
    Dept dept = session.selectOne("DEPT.getDeptById", 21);
    System.out.println(dept.getName());
}

resultMap还支持继承:

<resultMap id="deptMap" type="Dept">
    <id column="ID"  property="id" />
    <result column="NAME" property="name"/>
</resultMap>

<resultMap id="deptMapChild" type="Dept" extends="deptMap">
    <!--这里写新的<result>-->
</resultMap>

当我们又多个<resultMap>的时候,有些属性<result>的配置可以复用,就可以使用extends进行继承,上面的示例中,deptMapChild可以使用deptMap中的配置,具体的示例,请参照3.2.2中的deptMapWithEmployee

关联查询

3.2.1 一对一、多对一

本节的操作使用EmployeeMapper.xml,请提前创建文件并将EmployeeMapper.xml的namespace设置为”EMPLOYEE”。
Mybatis中一对一和多对一的配置一样。以员工EMPLOYEE为例。多个员工同属于一个部门,所以员工对部门是多对一。

员工实体类:

package pojo;
import java.util.Date;
public class Employee {
    private Integer id;
    private String name;
    private Dept dept;
    private String job;
    private Float salary;
    private Date hireDate;
    //getter/setter方法略
}

如果查询出员工的时候要查询出部门名,可以编写如下语句:

<select id="getEmployeeWithDept" resultMap="employeeMap">
    select E.ID, E.NAME ,E.JOB, E.SALARY, E.HIRE_DATE, E.DEPT_ID, D.NAME DEPT_NAME
    from EMPLOYEE E
    inner join DEPT D ON E.DEPT_ID=D.ID
</select>

对应的resultMap配置如下:

<resultMap id="employeeMap" type="Employee">
    <id property="id" column="ID"/>
    <result property="name" column="NAME"/>
    <result property="job" column="JOB"/>
    <result property="salary" column="SALARY"/>
    <result property="hireDate" column="HIRE_DATE"/>
    <result property="dept.id" column="DEPT_ID"/>
    <result property="dept.name" column="DEPT_NAME"/>
</resultMap>

通过dept.id和dept.name这种级联的方式给Employee类中dept这个属性的id和name赋值。

测试代码:

public void testManyToOne() {
    List<Employee> empList = session.selectList("EMPLOYEE.getEmployeeWithDept");
    for (Employee employee : empList) {
        System.out.println(employee.getName() + "的部门:"
                  + employee.getDept().getName());
    }
}

结果集employeeMap也可以使用association进行优化:

<resultMap id="employeeMap2" type="Employee">
    <id property="id" column="ID"/>
    <result property="name" column="NAME"/>
    <result property="job" column="JOB"/>
    <result property="salary" column="SALARY"/>
    <result property="hireDate" column="HIRE_DATE"/>
   <!--使用association将属于Dept的属性进行封装,不再使用dept.id-->
    <association property="dept" javaType="Dept">
        <result property="id" column="DEPT_ID"/>
        <result property="name" column="DEPT_NAME"/>
    </association>
</resultMap>

因为我们在DeptMapper.xml已经为Dept配置了结果集,所以上面的<association>可以通过resultMap引用其他的结果集:

<!--引用DEPT.deptMap-->
<association property="dept" resultMap="DEPT.deptMap">
</association>

<association>标签还有一个select属性,可以通过一个查询语句得到结果集并进行映射。如:

<resultMap id="employeeMap3" type="Employee">
    <id property="id" column="ID"/>
    <result property="name" column="NAME"/>
    <result property="job" column="JOB"/>
    <result property="salary" column="SALARY"/>
    <result property="hireDate" column="HIRE_DATE"/>
    <!--通过select调用DEPT.getDeptById-->
    <association property="dept" column="DEPT_ID" select="DEPT.getDeptById" >
    </association>
</resultMap>
<select id="getAllEmp" resultMap="employeeMap3">
    select * from EMPLOYEE
</select>

执行getAllEmp这个语句,我们只查询了EMPLOYEE表,没有查询DEPT表,在结果映射到employeeMap3的时候,associstion通过select指定的语句,去调用了DEPT.getDeptById进行查询,并将结果集封装到dept中。控制台打印sql如下:
在这里插入图片描述

可以看到,执行的流程是先查询出所有的EMPLOYEE,然后遍历结果集,根据每条查询结果的DEPT_ID去查询了DEPT表。直接使用join会执行一条语句,而在<associstion>中使用select,会执行n+1条。n是主表的查询结果集的条数,效率较低。

3.2.2 一对多、多对多

一对多、多对多的配置都是通过<collection>进行的。以一对多为例,一个部门DEPT有多个员工EMPLOYEE。

Dept实体类中添加Employee集合:

package pojo;
import java.util.List;
public class Dept {
    private Integer id;
    private String name;
    private List<Employee> employees;
    // getter/setter方法略
}

如果查询部门的时候要查询出部门所有的员工,sql语句为:

<select id="getDeptWith" resultMap="deptMapWithEmployee">
    select D.ID, D.NAME, E.ID EMP_ID, E.NAME EMP_NAME
    from DEPT D
    left join EMPLOYEE E ON E.DEPT_ID=D.ID
</select>

为了简化操作,我们只联合查询EMPLOYEE的ID和NAME两个属性。

对应的resultMap映射为:

<!--extends实现继承id=继承deptMap的resultMap-->
<resultMap id="deptMapWithEmployee" type="Dept" extends="deptMap">
    <!--collection用于映射一个集合-->
    <collection property="employees" ofType="Employee" >
        <id property="id" column="EMP_ID"/>
        <result property="name" column="EMP_NAME"/>
    </collection>
</resultMap>

<collection>也支持select属性:

<resultMap id="deptMapWithEmployee2" type="Dept" extends="deptMap">
    <!--collection用于映射一个集合-->
    <collection property="employees" ofType="Employee" 
                 select="EMPLOYEE.getEmpByDept" column="ID">
    </collection>
</resultMap>

<select id="getAllDept2" resultMap="deptMapWithEmployee2">
    select ID,NAME from DEPT
</select>

<collection>的select调用了EMPLOYEE.getEmpByDept,需要提前在EmployeeMapper.xml中写好对应的语句:

<select id="getEmpByDept" resultMap="employeeMap" parameterType="int">
    select ID,NAME FROM EMPLOYEE where DEPT_ID=#{deptid}
</select>

执行getAllDept2,可以看到控制台上的输出:
在这里插入图片描述
<association>一样,直接使用join会执行一条语句,而在<collection>中使用select,会执行n+1条。n是主表的查询结果集的条数,效率较低

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值