MyBatis多对一与一对多、自连接查询

多对一查询

例如根据学生查班级,使用<association>标签。
关联方式查询:通过多表关联的SQL语法进行查询, 需要使用join, on, …来实现查询。执行一条SQL语句就可以将所有需要的数据全部查询到。我们需要做的就是将查到的数据进行映射即可。实体类的属性名与表中的字段名一样时,默认不会自动映射,需要设置autoMapping=“true”,即可自动映射。通过association 映射实体类中包括的其他实体类。缺点:SQL语句复杂。

<mapper namespace="multiTableQueryMapper.UserMapper">
    <resultMap id="wu" type="Student" autoMapping="true">
        <id property="id" column="cid"/>
<!--        <result property="name" column="name"/>-->
<!--        <result property="gender" column="gender"/>-->
<!--        <result property="birthday" column="birthday"/>-->
        <association property="clazz" 
        javaType="Clazz" autoMapping="true">
            <id property="id" column="id"/>
<!--            <result property="name" column="name"/>-->
<!--            <result property="room" column="room"/>-->
        </association>
    </resultMap>
    <select id="selAll" resultMap="wu">
        select * from tb_student s left join tb_class c on c.id=s.cid
    </select>
<mapper>

N+1查询。一次查询出N个学生的信息,在根据N个学生的信息一次一次的查询N次,查出每个学生的班级信息。表示所有数据要获取到需要执行N+1条SQL语句。每次查询都是单表查询,查多次就拿到所有数据了。column是传递给select中查询id的参数。实体类的属性名与表中的字段名同名会自动映射。缺点:会对数据库多次访问。

<resultMap id="cao" type="Student">
    <id property="id" column="cid"/>
    <!--        <result property="name" column="name"/>-->
    <!--        <result property="gender" column="gender"/>-->
    <!--        <result property="birthday" column="birthday"/>-->
    <association property="clazz"
                javaType="Clazz"
                column="cid"
                select="multiTableQueryMapper.ClazzMapper.selById"/>
                <!--JavaType为查询到的返回实体类型-->
</resultMap>
<select id="selAll2" resultMap="cao">
    select * from tb_student
</select>
<mapper namespace="multiTableQueryMapper.ClazzMapper">
    <select id="selById" resultType="Clazz">
        select * from tb_class where id=#{id}
    </select>
</mapper>

一对多查询

关联查询。使用collection,javaType指定实际的类型而非像association指定泛型,使用ofType指定集合中的泛型。

<resultMap id="cao" type="Clazz" autoMapping="true">
    <collection property="students" javaType="list"
                ofType="Student" autoMapping="true">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
    </collection>
</resultMap>
<select id="selAll" resultMap="cao">
    select c.*, s.id sid, s.name sname, s.gender, s.birthday
    from tb_student s
    left join
    tb_class c
    on c.id=s.cid
</select>

N+1查询

<resultMap id="kao" type="Clazz">
    <!--如果这一列作为参数继续传递, 会导致自动映射失败-->
    <id property="id" column="id"/>
    <collection property="students" javaType="list"
                ofType="Student" column="id"
                select="oneToMutil.UserMapper.selById"/>
</resultMap>
<select id="selAll2" resultMap="kao">
    select * from tb_class
</select>
<select id="selById" resultType="Student">
    select * from tb_student where cid=#{id}
</select>

关联查询与N+1对比

关联查询:
sql语句是关联语法, 需要使用join…on…
只需要执行1条SQL语句
默认情况下, 不会自动映射, 可以通过设置autoMapping=true开启自动映射
N+1查询:
SQL语句都是单表查询
需要执行N+1次查询才能得到结果
默认情况下, 就会自动映射.

自连接

N+1根据据领导编号查询树结构员工信息。员工号作为要查询的上级管理者编号,做n次查询。

<resultMap id="tree" type="Emp">
    <id property="empno" column="empno"/>
    <!--当继续查询的sql在当前命名空间下时, 命名空间可以省略-->
    <collection property="emps" javaType="list"
                ofType="Emp"
                column="empno"
                select="sel4Tree"/>
</resultMap>
<select id="sel4Tree" resultMap="tree">
    select * from tb_emp
    <where>
        <choose>
            <when test="mgr==null">
                and mgr is null
            </when>
            <otherwise>
                and mgr=#{mgr}
            </otherwise>
        </choose>
    </where>
</select>
public List<Emp> sel4Tree(Integer mgr);

业务装配实现自连接

只需要查询一次,通过自定义代码实现业务装配。

public void test1() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    nPlusOne mapper = sqlSession.getMapper(nPlusOne.class);
    List<Emp> emps = mapper.selAll();
    List<Emp> tree = listToTree(emps);
    for (Emp emp : tree) {
        System.out.println(emp);
    }
}

private List<Emp> listToTree(List<Emp> emps) {
    List<Emp> empList = new ArrayList<>();
    Map<Integer, Emp> empMap = new HashMap<>();
//        封装到map可以快速获取管理者,不用直接遍历,减少时间复杂度
    for (Emp emp : emps) {
        empMap.put(emp.getEmpno(), emp);
    }
//        遍历员工并添加到管理者中
    for (Emp emp : emps) {
        if (emp.getMgr()==null){
            empList.add(emp);
            continue;
        }
//            先通过员工信息中的管理者编号获取管理者,在添加管理者中
//            实体类中的list不new会报空指针异常
        empMap.get(emp.getMgr()).getEmps().add(emp);
    }
    return empList;
}
<select id="selAll" resultType="Emp">
    select * from tb_emp
</select>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值