Spring+SpringMVC+MyBatis深入学习及搭建(六)——MyBatis关联查询

在实际的项目开发中,数据库表之间往往存在着各种关联关系,如一对一、一对多、多对多等。MyBatis 作为一款优秀的持久层框架,提供了强大的关联查询功能,能够方便地处理这些表间关联。本文将深入探讨 MyBatis 的关联查询,包括一对一、一对多和多对多关联查询的实现方式,并结合示例代码进行详细讲解。

目录#

  1. 一对一关联查询
    • 需求场景
    • 实现方式
    • 示例代码
  2. 一对多关联查询
    • 需求场景
    • 实现方式
    • 示例代码
  3. 多对多关联查询
    • 需求场景
    • 实现方式
    • 示例代码
  4. 总结
  5. 参考资料

1. 一对一关联查询#

需求场景#

在数据库中,一个用户可能对应一个详细的用户信息,如用户的联系方式、地址等。在查询用户信息时,往往需要同时查询其对应的详细信息,这就是一对一关联查询的典型场景。

实现方式#

MyBatis 实现一对一关联查询主要有两种方式:嵌套查询和嵌套结果。

  • 嵌套查询:通过执行多个 SQL 语句,先查询主表数据,再根据主表数据的关联字段查询关联表数据。
  • 嵌套结果:通过一个 SQL 语句查询主表和关联表的数据,然后在映射文件中进行结果映射。

示例代码#

假设我们有两个表:user 表和 user_info 表,它们通过 user_id 进行关联。

实体类#

// User.java
public class User {
    private Integer id;
    private String username;
    private UserInfo userInfo;
    // 省略 getter 和 setter 方法
}
 
// UserInfo.java
public class UserInfo {
    private Integer id;
    private String phone;
    private String address;
    // 省略 getter 和 setter 方法
}

映射文件(嵌套查询方式)#

<mapper namespace="com.example.mapper.UserMapper">
    <select id="getUserById" resultMap="UserResultMap">
        SELECT * FROM user WHERE id = #{id}
    </select>
    <select id="getUserInfoByUserId" resultType="com.example.entity.UserInfo">
        SELECT * FROM user_info WHERE user_id = #{userId}
    </select>
    <resultMap id="UserResultMap" type="com.example.entity.User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <association property="userInfo" column="id" select="getUserInfoByUserId"/>
    </resultMap>
</mapper>

映射文件(嵌套结果方式)#

<mapper namespace="com.example.mapper.UserMapper">
    <select id="getUserById" resultMap="UserResultMap">
        SELECT u.id, u.username, ui.id as info_id, ui.phone, ui.address
        FROM user u
        LEFT JOIN user_info ui ON u.id = ui.user_id
        WHERE u.id = #{id}
    </select>
    <resultMap id="UserResultMap" type="com.example.entity.User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <association property="userInfo" javaType="com.example.entity.UserInfo">
            <id property="id" column="info_id"/>
            <result property="phone" column="phone"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
</mapper>

2. 一对多关联查询#

需求场景#

在数据库中,一个部门可能有多个员工,在查询部门信息时,需要同时查询该部门下的所有员工信息,这就是一对多关联查询的典型场景。

实现方式#

MyBatis 实现一对多关联查询同样可以使用嵌套查询和嵌套结果两种方式。

示例代码#

假设我们有两个表:department 表和 employee 表,它们通过 department_id 进行关联。

实体类#

// Department.java
public class Department {
    private Integer id;
    private String departmentName;
    private List<Employee> employees;
    // 省略 getter 和 setter 方法
}
 
// Employee.java
public class Employee {
    private Integer id;
    private String employeeName;
    // 省略 getter 和 setter 方法
}

映射文件(嵌套查询方式)#

<mapper namespace="com.example.mapper.DepartmentMapper">
    <select id="getDepartmentById" resultMap="DepartmentResultMap">
        SELECT * FROM department WHERE id = #{id}
    </select>
    <select id="getEmployeesByDepartmentId" resultType="com.example.entity.Employee">
        SELECT * FROM employee WHERE department_id = #{departmentId}
    </select>
    <resultMap id="DepartmentResultMap" type="com.example.entity.Department">
        <id property="id" column="id"/>
        <result property="departmentName" column="department_name"/>
        <collection property="employees" column="id" select="getEmployeesByDepartmentId"/>
    </resultMap>
</mapper>

映射文件(嵌套结果方式)#

<mapper namespace="com.example.mapper.DepartmentMapper">
    <select id="getDepartmentById" resultMap="DepartmentResultMap">
        SELECT d.id, d.department_name, e.id as employee_id, e.employee_name
        FROM department d
        LEFT JOIN employee e ON d.id = e.department_id
        WHERE d.id = #{id}
    </select>
    <resultMap id="DepartmentResultMap" type="com.example.entity.Department">
        <id property="id" column="id"/>
        <result property="departmentName" column="department_name"/>
        <collection property="employees" ofType="com.example.entity.Employee">
            <id property="id" column="employee_id"/>
            <result property="employeeName" column="employee_name"/>
        </collection>
    </resultMap>
</mapper>

3. 多对多关联查询#

需求场景#

在数据库中,一个学生可以选择多门课程,一门课程也可以被多个学生选择,这就是多对多关联查询的典型场景。通常需要通过一个中间表来建立学生和课程之间的关联。

实现方式#

多对多关联查询可以通过嵌套查询和嵌套结果两种方式实现,核心是处理好中间表的关联。

示例代码#

假设我们有三个表:student 表、course 表和 student_course 中间表。

实体类#

// Student.java
public class Student {
    private Integer id;
    private String studentName;
    private List<Course> courses;
    // 省略 getter 和 setter 方法
}
 
// Course.java
public class Course {
    private Integer id;
    private String courseName;
    // 省略 getter 和 setter 方法
}

映射文件(嵌套查询方式)#

<mapper namespace="com.example.mapper.StudentMapper">
    <select id="getStudentById" resultMap="StudentResultMap">
        SELECT * FROM student WHERE id = #{id}
    </select>
    <select id="getCoursesByStudentId" resultType="com.example.entity.Course">
        SELECT c.*
        FROM course c
        JOIN student_course sc ON c.id = sc.course_id
        WHERE sc.student_id = #{studentId}
    </select>
    <resultMap id="StudentResultMap" type="com.example.entity.Student">
        <id property="id" column="id"/>
        <result property="studentName" column="student_name"/>
        <collection property="courses" column="id" select="getCoursesByStudentId"/>
    </resultMap>
</mapper>

映射文件(嵌套结果方式)#

<mapper namespace="com.example.mapper.StudentMapper">
    <select id="getStudentById" resultMap="StudentResultMap">
        SELECT s.id, s.student_name, c.id as course_id, c.course_name
        FROM student s
        LEFT JOIN student_course sc ON s.id = sc.student_id
        LEFT JOIN course c ON sc.course_id = c.id
        WHERE s.id = #{id}
    </select>
    <resultMap id="StudentResultMap" type="com.example.entity.Student">
        <id property="id" column="id"/>
        <result property="studentName" column="student_name"/>
        <collection property="courses" ofType="com.example.entity.Course">
            <id property="id" column="course_id"/>
            <result property="courseName" column="course_name"/>
        </collection>
    </resultMap>
</mapper>

总结#

MyBatis 的关联查询功能为处理数据库表间关联提供了强大的支持。通过嵌套查询和嵌套结果两种方式,我们可以方便地实现一对一、一对多和多对多关联查询。在实际开发中,需要根据具体的业务需求和性能要求选择合适的实现方式。

参考资料#

  • 《MyBatis 官方文档》
  • 《Spring+MyBatis 企业应用实战》

以上就是关于 MyBatis 关联查询的详细介绍,希望对你有所帮助。