MyBatis第六篇:关联查询一定要会的!

这是MyBatis学习的第六篇,继续吧~


前言

在实际开发中我们的数据表都是有关联关系的,我们查询也都是几张表联合起来进行查询的。例如,订单表和用户表,员工表和部门表等等吧,总之十分的重要,我们在进行多表查询的时候会介绍两种方式:联合查询和分表查询


一、多对一

1.联合查询

模拟多个员工对应一个部门的情况。
1.创建表:
在这里插入图片描述

2.实体类:

//员工实体类
public class Employee {
    private Integer id;
    private String name;
    private String gender;
    private Integer age;
    private Department department;
    }
//部门实体类
public class Department {
    private Integer id;
    private String name;
    }

3.Mapper接口

public interface EmployMapper {
    //根据员工编号获取员工信息和员工部门
    public Employee getEmployeeById(Integer id);
    }

4.映射文件:

    <select id="getEmployeeById" resultMap="resultEmployMap" >
        select e.*,d.* from employee e,department d where e_depart_id=d_id and e_id=#{id}
    </select>
    <resultMap id="resultEmployMap" type="Employee">
        <id column="e_id" property="id"></id>
        <result column="e_name" property="name"></result>
        <result column="e_gender" property="gender"></result>
        <result column="e_age" property="age"></result>
        <association property="department" javaType="Department">
            <id column="d_id" property="id"></id>
            <result column="d_name" property="name"></result>
        </association>
    </resultMap>
</mapper>
简单解释:联合查询就是将表链接起来,使用约束条件进行筛选符合
条件的结果集。其中因为有复杂字段的参与,使用特殊的标签的进行
association表示联合。property表示复杂属性的属性名,javaType
表示负责属性的属性类型。其中的id和result就是复杂属性的属性和
数据表中的字段进行一一对应的关系。

2.分表查询

分表查询的思路就是我们要找员工的部门信息,首先就是要找到员工的部门编号,在使用这个员工编号去查询对应的部门信息,并将部门信息存储在员工类中的复杂属性中去。
在这里插入图片描述
首先我们要知道分表查询对应的sql语句是两条,那么就需要我们写两个接口,对应两个映射文件
1.Mapper接口

//员工接口
public interface EmployeeMapper{
      //根据员工编号获取员工信息和员工部门
    public Employee getEmployeeById(Integer id);
}
//部门接口
public interface DepartMapper{
    //根据部门id找到对应的部门
    public Department getDepartmentByIdT(Integer id);
}

2.映射文件:

Employee的映射文件

    <select id="getEmployeeById" resultMap="huhuuhu" >
        select e.*from employee e where e_id=#{id}
    </select>
    <resultMap id="huhuuhu" type="Employee">
        <id column="e_id" property="id"></id>
        <result column="e_name" property="name"></result>
        <result column="e_gender" property="gender"></result>
        <result column="e_age" property="age"></result>
        <association property="department" javaType="Department"
        column="e_depart_id" select="com.offcn.mapper.DepartMapper.getDepartmentByIdT"
        >
        </association>
    </resultMap>

association 用于映射多对一关系对象的,
Property 关联对象的复杂属性
javaType: 复杂属性的类型
Column: 取结果集中指定类的值,作为 select 查询的输入值
Select: 指定另一次查询,使用全限名

DepertMapper的映射文件

    <select id="getDepartmentByIdT" resultMap="DepartmentByIdTW">
        select * from department where d_id=#{id}
    </select>
    <resultMap id="DepartmentByIdTW" type="Department">
        <id column="d_id" property="id"></id>
        <result column="d_name" property="name"></result>
    </resultMap>

两种方式的比较:
查看生成的sql语句:
联合查询
在这里插入图片描述
分表查询
在这里插入图片描述
分表查询步骤繁琐,但是在效率上会更高一下!

二、一对多

这个在实际开发中也是比较使用的例如:一个部门可以对应多个员工,一个用可以拥有多个订单等……

1.联合查询

我们在定义实体类的时候,通过一个集合来代表实体类的中所对应的对象。这时候我们要用到collection标签。
数据表依旧采用员工部门表
在这里插入图片描述
1.对应的实体类

//员工类
public class Employee{
    private Integer id;
    private String name;
    private String gender;
    private Integer age;
}
//部门类
public class Department{
    private Integer id;
    private String name;
    //这是使用集合的形式,将部门对应的多个员工进行存储。来实现一对多
    public List<Employee> emps;
}

2.Mpper接口

public interface DepartMapper{
    //根据部门Id找到对应的员工信息
    public Department getDepartmentByDid(Integer did);
}

3.对应的xml映射

    <select id="getDepartmentByDid" resultMap="OneToMang">
        select e.*,d.* from department d,employee e where e.e_depart_id=d.d_id and d.d_id=#{did}
    </select>
    <resultMap id="OneToMang" type="Department">
        <id column="d_id" property="id"></id>
        <result column="d_name" property="name"></result>
        <collection property="emps" ofType="Employee" >
            <id column="e_id" property="id"></id>
            <result column="e_name" property="name"></result>
            <result column="e_gender" property="gender"></result>
            <result column="e_age" property="age"></result>
        </collection>
    </resultMap>
</mapper>

collection:表示映射的是复杂属性集合
property:对应复杂属性的属性名
ofType:集合中的元素的类型
其中的id和result就表示映射的关联,column数据表中的字段,property就是映射的属性名(实体类中的属性名)column和property是一一对应的关系

3.测试类:

    @Test
    public void show16() {
        SqlSession session = MyBatisUtils.getSession();
        DepartMapper mapper = session.getMapper(DepartMapper.class);
        Department depart = mapper.getDepartmentByDid(1);
        List<Employee> emps = depart.getEmps();
        for (Employee emp : emps) {
            System.out.println(depart.getName()+"=="+emp);
        }
        MyBatisUtils.closeSession(session);
    }

看一下生成的sql语句:
在这里插入图片描述

2.分表查询

分表查询的思路和上边多对一查询思路是一样的,但是就是标签使用的是不一样的,一个对象的话使用的association而一个集合的话使用的collection.
1.各自对应的Mapper接口

//部门接口
public interface DepartMapper{
    public Department getDepartmentByIdTW(Integer id);
}
//员工接口
public interface EmployMapper{
    public Employee getEmployeeById(Integer id);
}

2.主要是映射文件!!

DepartMapper对应的映射文件
    <select id="getDepartmentByIdTW" resultMap="DepartmentByIdTW">
        select * from department where d_id=#{id}
    </select>
    <resultMap id="DepartmentByIdTW" type="Department">
        <id column="d_id" property="id"></id>
        <result column="d_name" property="name"></result>
    </resultMap>
        <collection property="emps" ofType="Employee" column="d_id"
        select="com.offcn.mapper.EmployMapper.getEmployeeById"
        >
        </collection>

EmployMapper对应的映射文件

    <select id="getEmployeeById" resultMap="hahaha" >
        select e.* from employee e where e_depart_id=#{id}
    </select>
    <resultMap id="hahaha" type="Employee">
        <id column="e_id" property="id"></id>
        <result column="e_name" property="name"></result>
        <result column="e_gender" property="gender"></result>
        <result column="e_age" property="age"></result>
    </resultMap>

collection 用于映射一对多关系对象的,
Property 关联对象的复杂属性名
ofType: 集合中元素的类型
Column: 取结果集中指定列的值,作为 select 查询的输入值
Select: 指定另一次查询,使用全限名

测试类和上述一模一样,但是看一下查询的sql语句
在这里插入图片描述
此时有两条sql语句。这种方式更符合我们的思维习惯,查出一个结果作为另一个结果的输入,然后查询想要的结果。


三、多对多

举例:一个老师对应多个学生,一个学生可以有多个老师。
表间关系:

在这里插入图片描述

1.联合查询

对应的实体类:

//学生类
public class Teacher {
    private Integer id;
    private String name;
    private List<StudentTeacher> studentTeacherList;
    }
//中间表
public class StudentTeacher {
    private Integer sid;
    private Integer tid;
    private Student student;
    private Teacher teacher;    
    }
    //教师类
public class Teacher {
    private Integer id;
    private String name;
    private List<StudentTeacher> studentTeacherList;    
    }

需求:通过教师id找到对应的学生

    <select id="getStudentByTid" resultMap="StudentResultMap">
     select t.*,s.*,st.* from teacher t,student s,student_teacher st
     where s.s_id = st.st_sid and st.st_tid=t.t_id and t.t_id = #{id}
    </select>
    <resultMap id="StudentResultMap" type="Teacher">
        <id column="t_id" property="id"></id>
        <result column="t_name" property="name"></result>
        <collection property="studentTeacherList" ofType="StudentTeacher">
            <result column="st_sid" property="sid"></result>
            <result column="st_tid" property="tid"></result>
            <association property="student" javaType="Student">
                <id column="s_id" property="id"></id>
                <result column="s_name" property="name"></result>
            </association>
        </collection>
    </resultMap>

注意:此时我的中间表是使用两个字段作为主键的那么在映射的时候就不能使用id这个标签进行映射,要使用result标签
多对多查询可以看作是多对一和一对多的联合使用,我们可以看到collection标签里边嵌套了association标签。

测试类:

    @Test
    public void show17() {
        SqlSession session = MyBatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getStudentByTid(2);
        for (StudentTeacher studentTeacher : teacher.getStudentTeacherList()) {
            System.out.println("教师姓名:"+teacher.getName()+"==="+"学生姓名:"+studentTeacher.getStudent().getName());
        }
        MyBatisUtils.closeSession(session);
    }

结果:
在这里插入图片描述

2.分表查询

1.Mapper接口

//教师实体类对应的接口
public interface TeacherMapper {
    public Teacher getTeachersByTid(Integer tid);
}
//中间表对应的接口
public interface StudentTeacherMapper {
    //返回学生对应的集合
    public List<StudentTeacher> getStudentAndTeacher(Integer id);
}
//StudentMapper接口
public interface StudentMapper {
    //根据学生id获取学生信息
    public Student getStudentsBySid(Integer sid);
}

2.映射文件

<select id="getTeachersByTid" resultMap="TeacherResult">
    select * from teacher where t_id = #{id}
</select>
<resultMap id="TeacherResult" type="Teacher">
    <id column="t_id" property="id"></id>
    <result column="t_name" property="name"></result>
    <collection property="studentTeacherList" ofType="StudentTeacher"
    column="t_id" select="com.offcn.mapper.StudentTeacherMapper.getStudentAndTeacher"
    >
    </collection>
</resultMap>

在这里插入图片描述

    <select id="getStudentAndTeacher" resultMap="StudentTeacher2">
      select * from student_teacher where st_tid=#{sid}
    </select>
    <resultMap id="StudentTeacher2" type="StudentTeacher">
      <result column="st_sid" property="sid"></result>
        <result column="st_did" property="did"></result>
        <association property="student" javaType="Student"
        column="st_sid" select="com.offcn.mapper.StudentMapper.getStudentsBySid"
        >
        </association>
    </resultMap>

在这里插入图片描述

    <select id="getStudentsBySid" resultMap="StudentreResultMap">
    select * from student where s_id = #{id}
   </select>
    <resultMap id="StudentreResultMap" type="Student">
        <id column="s_id" property="id"></id>
        <result column="s_name" property="name"></result>
    </resultMap>

测试类:

    @Test
    public void show18() {
        SqlSession session = MyBatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeachersByTid(1);
        for (StudentTeacher studentTeacher : teacher.getStudentTeacherList()) {
            System.out.println("教师姓名:"+teacher.getName()+"==="+"学生姓名:"+studentTeacher.getStudent().getName());
        }
        MyBatisUtils.closeSession(session);
    }
}

结果:
在这里插入图片描述
我们可以看到是三条sql语句

四、一对一

现实生活中还有一种情况就是一一对应的关系,即一对一关系,例如身份证号和人。一对一的关系使用起来相对简单,写的时候就简写了……

1.联表查询

数据表准备:
在这里插入图片描述
1.实体类:

//Person类
public class Person{
    private Integer id;
    private String name;
    private IdCard idCard;
}
//Idcard类
public class IdCard{
    private int id;
    private String card;
    private Person person;
}

2.Mapper接口

public interface PersonMapper {
    //通过个人id找到对应的身份证号
    public Person getPersonByCard(Integer id);
    }

3.映射文件

    <select id="getPersonByCard" resultMap="PersonMapperResult">
        SELECT p.*,c.* FROM person p,idcard c WHERE c.c_person_id=p.p_id AND p.p_id = #{id};
    </select>
    <resultMap id="PersonMapperResult" type="Person">
        <id column="p_id" property="id"></id>
        <result column="p_name" property="name"></result>
        <association property="idCard" javaType="IdCard">
            <id column="c_cardno" property="card"></id>
            <result column="c_person_id" property="id"></result>
        </association>
    </resultMap>

测试类:

    @Test
    public void show5() {
        SqlSession session = MyBatisUtils.getSession();
        PersonMapper mapper = session.getMapper(PersonMapper.class);
        Person person = mapper.getPersonByCard(1);
        System.out.println(person.getName() + "=" + person.getIdCard().getCard());
    }

结果:
在这里插入图片描述

2.分表查询

1.接口

public interface PersonMapper {
    //通过人id找到身份账号
    public Person getPersonByCardT(Integer id);
}

2.Mapper接口的映射文件

    <select id="getPersonByCardT" resultMap="PersonByCardTResult">
        select * from person where p_id=#{id}
    </select>
    <resultMap id="PersonByCardTResult" type="Person">
        <id column="p_id" property="id"></id>
        <result column="p_name" property="name"></result>
        <association property="idCard" javaType="IdCard" column="p_id"
                     select="com.offcn.mapper.IdCardMapper.getIdCardById">
        </association>
    </resultMap>

下一次查询

    <select id="getIdCardById" resultMap="IdCardByIdResult">
select * from idcard where c_person_id = #{id}
    </select>
    <resultMap id="IdCardByIdResult" type="IdCard">
        <id column="c_cardno" property="card"></id>
        <result column="c_person_id" property="id"></result>
    </resultMap>

测试类和上述一致

结果:
在这里插入图片描述

总结

虽然MyBatis提供的关联查询功能比较强大,但是还是建议使用单表查询,然后将结果进行组装(上述介绍的分表查询,写多条sql语句而不仅仅是一条),这样可以提高查询效率的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Mybatis是一种Java持久层框架,它提供了强大的关联查询功能。根据表与表间的关联关系的不同,关联查询分为四种:一对一关联查询、一对多关联查询、多对一关联查询多对多关联查询[^1]。 一对一关联查询是指两个表之间存在一对一的关系,可以通过在查询语句中使用嵌套查询或者使用关联映射来实现。嵌套查询是指在主查询中嵌套子查询,通过子查询获取关联表的数据。关联映射是指在主查询的结果集中包含关联表的数据,通过配置关联映射来实现。以下是一个示例代码演示了如何在Mybatis中进行一对一关联查询: ```xml <!-- 定义关联映射 --> <resultMap id="userMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="address" column="address"/> <association property="card" javaType="Card"> <id property="id" column="card_id"/> <result property="cardNo" column="card_no"/> </association> </resultMap> <!-- 执行关联查询 --> <select id="getUserWithCard" resultMap="userMap"> SELECT u.id, u.name, u.address, c.id as card_id, c.card_no FROM user u INNER JOIN card c ON u.card_id = c.id WHERE u.id = #{id} </select> ``` 以上代码中,定义了一个关联映射`userMap`,其中包含了`User`和`Card`两个实体类的属性映射关系。在执行关联查询时,通过`INNER JOIN`将`user`表和`card`表关联起来,并通过`WHERE`条件限定查询结果。最终将查询结果映射到`User`对象中,其中`User`对象中的`card`属性也会被自动填充。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值