MyBatis联合查询

1、联合查询简介

  • 级联关系是一个数据库实体的概念,有 3 种级联关系,分别是一对一级联、一对多级联以及多对多级联。级联的优点是获取关联数据十分方便,但是级联过多会增加数据库系统的复杂度,同时降低系统的性能。 MyBatis提供了方便的一对一和多对多查询,而多对多查询可以由两个一对多查询组成。

2、级联属性查询数据

  • ①使用级联属性查询数据之前,需要在mysql建立好所需的表,现在在mysql的User数据库里新建Student表(学生表)和Grade表(班级表),且逻辑是一个班级有多个学生,而一个学生只属于一个班级。

  • ②根据https://perfectcode.top/2020/12/24/%E6%90%AD%E5%BB%BAMyBatis/#more新建一个MyBatis项目,并创建好数据库表对应的bean。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public class Student {
    private int sId;
    private String sName;
    private Grade grade;

    public int getsId() {
    return sId;
    }

    public void setsId(int sId) {
    this.sId = sId;
    }

    public String getsName() {
    return sName;
    }

    public void setsName(String sName) {
    this.sName = sName;
    }

    public Grade getGrade() {
    return grade;
    }

    public void setGrade(Grade grade) {
    this.grade = grade;
    }

    @Override
    public String toString() {
    return "Student{" +
    "sId=" + sId +
    ", sName='" + sName + '\'' +
    ", grade=" + grade +
    '}';
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public class Grade {
    private int gId;
    private String gName;
    private List<Student> students;

    public int getgId() {
    return gId;
    }

    public void setgId(int gId) {
    this.gId = gId;
    }

    public String getgName() {
    return gName;
    }

    public void setgName(String gName) {
    this.gName = gName;
    }

    public List<Student> getStudents() {
    return students;
    }

    public void setStudents(List<Student> students) {
    this.students = students;
    }

    @Override
    public String toString() {
    return "Grade{" +
    "gId=" + gId +
    ", gName='" + gName + '\'' +
    ", students=" + students +
    '}';
    }
    }
  • ③新建StudentDao和StudentMapper.xml配置好查询语句,假设要根据学生id查找其所在班级信息:

    1
    2
    3
    4
    public interface StudentDao {

    Student getStudentById(Integer sId);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?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.example.dao.StudentDao">

    <resultMap id="myResultMap" type="com.example.bean.Student">
    <id property="sId" column="s_id"/>
    <result property="sName" column="s_name"/>
    <result property="grade.gId" column="g_id"/>
    <result property="grade.gName" column="g_name"/>
    </resultMap>

    <select id="getStudentById" resultMap="myResultMap">
    select s.s_id, s.s_name, g.g_id, g.g_name
    from student s
    join grade g on g.g_id = s.g_id
    where s.s_id = #{sId}
    </select>
    </mapper>
  • ④测试级联属性查询数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class MybatisTest {
    public static void main(String[] args) throws IOException {
    //1.根据全局配置文件创建一个sqlSessionFactory
    //SqlSessionFactory是SqlSession工厂,负责创建SqlSession对象
    //SqlSession:sql会话(代表和数据库的一次会话)
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2.获取和数据库的一次会话:getConnection()
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3.使用SqlSession操作数据库,先获取到dao接口实现
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);

    //4.调用方法
    Student studentById = mapper.getStudentById(1);
    System.out.println(studentById);
    }
    }

    执行结果成功查询到id为1的学生的信息。

3、使用association查询数据

  • 在 MyBatis 中可以通过 元素的子元素 处理一对一级联查询。在 元素中通常使用以下属性。

    • property:指定映射到实体类的对象属性。

    • column:指定表中对应的字段(即查询返回的列名)。

    • javaType:指定映射到实体对象属性的类型。

    • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

      • ①将上面用级联属性查询例子改成用来进行一对一查询,此时的StudentMapper.xml内容如下,其它不变:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        <?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.example.dao.StudentDao">

        <resultMap id="myResultMap" type="com.example.bean.Student">
        <id property="sId" column="s_id"/>
        <result property="sName" column="s_name"/>
        <association property="grade" javaType="com.example.bean.Grade">
        <id property="gId" column="g_id"/>
        <result property="gName" column="g_name"/>
        </association>
        </resultMap>

        <select id="getStudentById" resultMap="myResultMap">
        select s.s_id, s.s_name, g.g_id, g.g_name
        from student s
        join grade g on g.g_id = s.g_id
        where s.s_id = #{sId}
        </select>
        </mapper>
      • ②测试后发现打印出同样的结果:

    • 如果使用 的select属性,则将StudentMapper.xml改为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      <?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.example.dao.StudentDao">

      <resultMap id="myResultMap" type="com.example.bean.Student">
      <id property="sId" column="s_id"/>
      <result property="sName" column="s_name"/>
      <association property="grade" select="com.example.dao.GradeDao.getGradeByIdSimple"
      column="g_id">
      </association>
      </resultMap>

      <select id="getStudentById" resultMap="myResultMap">
      select * from student where s_id = #{sId}
      </select>
      </mapper>

      同时需要新建GradeDao和GradeMapper.xml,内容分别如下:

      1
      2
      3
      public interface GradeDao {
      Grade getGradeByIdSimple(Integer gId);
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?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.example.dao.GradeDao">

      <select id="getGradeByIdSimple" resultType="com.example.bean.Grade">
      select * from grade where g_id = #{gId}
      </select>
      </mapper>

      测试结果也一样:

4、使用collection查询数据

  • 在 MyBatis 中可以通过 元素的子元素 处理一对多级联查询。

    • ①假设需要根据班级id查询所有的学生信息,此时需要用到 来进行一对多查询。此时的GradeDao和GradeMapper.xml内容如下:

      1
      2
      3
      4
      public interface GradeDao {

      Grade getGradeById(Integer gId);
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      <?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.example.dao.GradeDao">

      <resultMap id="myResultMap" type="com.example.bean.Grade">
      <id property="gId" column="g_id"/>
      <result property="gName" column="g_name"/>
      <collection property="students" ofType="com.example.bean.Student">
      <id property="sId" column="s_id"/>
      <result property="sName" column="s_name"/>
      </collection>
      </resultMap>

      <select id="getGradeById" resultMap="myResultMap">
      select g.g_id, g.g_name, s.s_id, s.s_name
      from grade g
      join student s on s.g_id = g.g_id
      where g.g_id = #{gId}
      </select>
      </mapper>
    • ②测试类及测试结果如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      public class MybatisTest {
      public static void main(String[] args) throws IOException {
      //1.根据全局配置文件创建一个sqlSessionFactory
      //SqlSessionFactory是SqlSession工厂,负责创建SqlSession对象
      //SqlSession:sql会话(代表和数据库的一次会话)
      String resource = "mybatis-config.xml";
      InputStream inputStream = Resources.getResourceAsStream(resource);
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

      //2.获取和数据库的一次会话:getConnection()
      SqlSession sqlSession = sqlSessionFactory.openSession();

      //3.使用SqlSession操作数据库,先获取到dao接口实现
      GradeDao mapper = sqlSession.getMapper(GradeDao.class);

      //4.调用方法
      Grade gradeById = mapper.getGradeById(1);
      System.out.println(gradeById);
      }
      }
    • 如果也是用select属性,则将GradeMapper.xml改为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      <?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.example.dao.GradeDao">

      <resultMap id="myResultMap" type="com.example.bean.Grade">
      <id property="gId" column="g_id"/>
      <result property="gName" column="g_name"/>
      <collection property="students" select="com.example.dao.StudentDao.getStudentsByGradeId"
      column="g_id">
      </collection>
      </resultMap>

      <select id="getGradeById" resultMap="myResultMap">
      select * from grade where g_id = #{gId};
      </select>
      </mapper>

      同时StudentDao和StudentMapper.xml内容分别如下:

      1
      2
      3
      public interface StudentDao {
      List<Student> getStudentsByGradeId(Integer gId);
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?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.example.dao.StudentDao">

      <select id="getStudentsByGradeId" resultType="com.example.bean.Student">
      select * from student where g_id = #{gId}
      </select>
      </mapper>

      测试结果为: