在 MyBatis 中,关联查询(Association Mapping)用于在查询中映射多个表之间的关系,常见的有以下三种类型:
- 一对一(One-to-One):一个对象与另一个对象之间存在唯一对应关系
- 一对多(One-to-Many):一个对象包含多个对象
- 多对多(Many-to-Many):两个对象之间通过中间表存在多对多的关系
MyBatis 通过 resultMap
、association
和 collection
标签来配置关联查询,并将查询结果自动映射为 Java 对象。
🏠 1. 一对一关联查询
场景:
- 一个
User
关联一个Address
User
表中的address_id
外键关联Address
表的id
① 建表示例
CREATE TABLE User (
id INT PRIMARY KEY,
name VARCHAR(50),
address_id INT,
FOREIGN KEY (address_id) REFERENCES Address(id)
);
CREATE TABLE Address (
id INT PRIMARY KEY,
city VARCHAR(50),
street VARCHAR(100)
);
② 定义 Java 类
User.java
public class User {
private int id;
private String name;
private Address address;
// getter & setter
}
Address.java
public class Address {
private int id;
private String city;
private String street;
// getter & setter
}
③ Mapper 映射文件
使用 <association>
进行一对一映射:
<mapper namespace="com.example.mapper.UserMapper">
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="address" column="address_id" javaType="Address" select="getAddressById"/>
</resultMap>
<!-- 获取用户信息 -->
<select id="getUserById" resultMap="userResultMap">
SELECT id, name, address_id FROM User WHERE id = #{id}
</select>
<!-- 通过 id 查询地址 -->
<select id="getAddressById" resultType="Address">
SELECT id, city, street FROM Address WHERE id = #{id}
</select>
</mapper>
④ Mapper 接口
public interface UserMapper {
User getUserById(int id);
}
🔥 说明
<association>
:定义一对一关联column="address_id"
:传递到select="getAddressById"
作为参数select="getAddressById"
:表示通过address_id
进行二次查询
⑤ SQL 执行过程
- 执行
getUserById()
方法 - 通过
address_id
触发getAddressById
查询 - 将查询结果封装成
Address
对象并注入到User
对象中
🏢 2. 一对多关联查询
场景:
- 一个
Department
下包含多个Employee
Employee
表中的department_id
外键关联Department
表的id
① 建表示例
CREATE TABLE Department (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE Employee (
id INT PRIMARY KEY,
name VARCHAR(50),
department_id INT,
FOREIGN KEY (department_id) REFERENCES Department(id)
);
② 定义 Java 类
Department.java
public class Department {
private int id;
private String name;
private List<Employee> employees;
// getter & setter
}
Employee.java
public class Employee {
private int id;
private String name;
private int departmentId;
// getter & setter
}
③ Mapper 映射文件
使用 <collection>
进行一对多映射:
<mapper namespace="com.example.mapper.DepartmentMapper">
<resultMap id="departmentResultMap" type="Department">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="employees" ofType="Employee">
<id property="id" column="employee_id"/>
<result property="name" column="employee_name"/>
</collection>
</resultMap>
<!-- 查询部门及其员工 -->
<select id="getDepartmentById" resultMap="departmentResultMap">
SELECT d.id, d.name, e.id AS employee_id, e.name AS employee_name
FROM Department d
LEFT JOIN Employee e ON d.id = e.department_id
WHERE d.id = #{id}
</select>
</mapper>
④ Mapper 接口
public interface DepartmentMapper {
Department getDepartmentById(int id);
}
🔥 说明
<collection>
:定义一对多关联ofType="Employee"
:表示集合中对象类型为Employee
- 通过
LEFT JOIN
关联查询
⑤ SQL 执行过程
- 执行
getDepartmentById()
方法 - 通过
LEFT JOIN
生成完整结果集 - 将结果集封装成
Department
对象,并填充employees
列表
🔗 3. 多对多关联查询
场景:
- 一个学生对应多个课程,一个课程也对应多个学生
- 使用中间表
student_course
维护多对多关系
① 建表示例
CREATE TABLE Student (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE Course (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE student_course (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Student(id),
FOREIGN KEY (course_id) REFERENCES Course(id)
);
② 定义 Java 类
Student.java
public class Student {
private int id;
private String name;
private List<Course> courses;
// getter & setter
}
Course.java
public class Course {
private int id;
private String name;
// getter & setter
}
③ Mapper 映射文件
<resultMap id="studentResultMap" type="Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="courses" ofType="Course" select="getCoursesByStudentId" column="id"/>
</resultMap>
<select id="getStudentById" resultMap="studentResultMap">
SELECT id, name FROM Student WHERE id = #{id}
</select>
<select id="getCoursesByStudentId" resultType="Course">
SELECT c.id, c.name
FROM Course c
JOIN student_course sc ON c.id = sc.course_id
WHERE sc.student_id = #{id}
</select>
🔥 说明
<collection>
定义集合映射select="getCoursesByStudentId"
触发二次查询- 多对多关系由中间表维护
🚀 4. 总结
关联关系 | 关键标签 | 触发方式 |
---|---|---|
一对一 | <association> | 通过外键或 JOIN 查询 |
一对多 | <collection> | 通过 JOIN 查询 |
多对多 | <collection> | 通过中间表和二次查询 |
✅ 推荐在 多对多 和 一对多 关系中使用 延迟加载(lazy loading) 来提升性能! 😎