Mybatis 映射关系
在 MyBatis 中,关系的映射主要通过
<association>
和<collection>
标签来处理,分别对应 一对一 和 一对多/ 多对多 关系。
1. 一对一 (One-to-One)
定义:
一个实体与另一个实体之间存在唯一的关联关系。例如,一个用户有唯一的身份证信息,一个学生有唯一的档案信息。
数据库设计:
- 使用 两个表,通过主键或唯一键进行关联。
- 两个表之间的关联通常是主键关联或唯一约束。
示例:
表1:user
(用户表)
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50)
);
表2:user_detail(用户详情表)
CREATE TABLE user_detail (
id BIGINT PRIMARY KEY,
address VARCHAR(100),
phone_number VARCHAR(20),
FOREIGN KEY (id) REFERENCES user(id)
);
关联说明:user.id
与 user_detail.id
是一对一的关系,每个用户只能有一条详细信息。
一对一映射
MyBatis 使用 <association>
标签来映射一对一的关系。
示例:用户与用户详情
-
表结构:
user
(用户表):id
,username
user_detail
(用户详情表):id
,address
,phone_number
对应实体类:
public class User {
private Long id;
private String username;
private UserDetail userDetail; // 一对一关系
}
public class UserDetail {
private Long id;
private String address;
private String phoneNumber;
}
ResultMap 配置
<resultMap id="userWithDetailMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<association property="userDetail" javaType="UserDetail">
<id property="id" column="detail_id"/>
<result property="address" column="address"/>
<result property="phoneNumber" column="phone_number"/>
</association>
</resultMap>
<select id="getUserWithDetail" resultMap="userWithDetailMap">
SELECT u.id, u.username, d.id AS detail_id, d.address, d.phone_number
FROM user u
LEFT JOIN user_detail d ON u.id = d.id
WHERE u.id = #{userId}
</select>
2. 一对多 (One-to-Many)
定义:
一个实体与另一个实体之间存在一对多的关联。例如,一个用户可以有多张订单,一个部门可以有多个员工。
数据库设计:
- 使用 两个表,通过外键关联。
- 在“多”的一方表中,添加一个外键指向“单”的一方表。
示例:
表1:user
(用户表)
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50)
);
表2:orders
(订单表)
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
order_number VARCHAR(20),
user_id BIGINT,
FOREIGN KEY (user_id) REFERENCES user(id)
);
关联说明:user.id
与 orders.user_id
是一对多的关系,每个用户可以有多张订单。
一对多映射
MyBatis 使用 <collection>
标签来映射一对多的关系。
示例:用户与订单
-
表结构:
user
(用户表):id
,username
orders
(订单表):id
,order_number
,user_id
对应实体类:
public class User {
private Long id;
private String username;
private List<Order> orders; // 一对多关系
}
public class Order {
private Long id;
private String orderNumber;
}
ResultMap 配置
<resultMap id="userWithOrdersMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="orderNumber" column="order_number"/>
</collection>
</resultMap>
<select id="getUserWithOrders" resultMap="userWithOrdersMap">
SELECT u.id AS user_id, u.username, o.id AS order_id, o.order_number
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{userId}
</select>
3. 多对多 (Many-to-Many)
定义:
两个实体之间存在多对多的关联。例如,一个学生可以选修多门课程,一门课程也可以有多个学生选修。
数据库设计:
- 使用 三个表,通过中间表来建立关联。
- 中间表通常包含两个外键,分别指向关联的两个表。
示例:
表1:student
(学生表)
CREATE TABLE student (
id BIGINT PRIMARY KEY,
name VARCHAR(50)
);
表2:course
(课程表)
CREATE TABLE course (
id BIGINT PRIMARY KEY,
course_name VARCHAR(50)
);
表3中间表:student_course
(学生课程关联表)
CREATE TABLE student_course (
student_id BIGINT,
course_id BIGINT,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
关联说明:student
和 course
通过 student_course
中间表建立多对多的关联,一个学生可以选修多门课程,一门课程也可以有多个学生。
多对多映射
MyBatis 使用 <collection>
标签来映射多对多的关系,通过中间表进行关联。
示例:学生与课程
-
表结构:
student
(学生表):id
,name
course
(课程表):id
,course_name
student_course
(中间表):student_id
,course_id
对应实体类:
public class Student {
private Long id;
private String name;
private List<Course> courses; // 多对多关系
}
public class Course {
private Long id;
private String courseName;
}
ResultMap 配置
<resultMap id="studentWithCoursesMap" type="Student">
<id property="id" column="student_id"/>
<result property="name" column="name"/>
<collection property="courses" ofType="Course">
<id property="id" column="course_id"/>
<result property="courseName" column="course_name"/>
</collection>
</resultMap>
<select id="getStudentWithCourses" resultMap="studentWithCoursesMap">
SELECT s.id AS student_id, s.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 = #{studentId}
</select>
4:区别总结
类型 | 定义 | 数据库设计 | 举例 |
---|---|---|---|
一对一 | 一个实体与另一个实体唯一关联 | 两个表,主键或唯一键关联 | 用户与用户详情 |
一对多 | 一个实体与多个实体关联 | 两个表,使用外键关联 | 用户与订单,部门与员工 |
多对多 | 多个实体之间互相关联 | 三个表,通过中间表建立关联 | 学生与课程,用户与角色 |
选择关系类型的依据
- 一对一:当两个表中的数据一一对应且每个记录仅能有一个关联记录时,使用一对一。例如用户与其身份证信息。
- 一对多:当一个表的记录可以对应另一个表中的多个记录时,使用一对多。例如用户与订单、部门与员工。
- 多对多:当两个表中的记录互相可以有多个关联时,使用多对多。例如学生与课程、用户与角色。
实例化理解
一对一:
用户:张三 -> 身份证信息:3701XXXXXXXXXXXX
一对多:
用户:张三 -> 订单:#1001, #1002, #1003
多对多:
学生:张三 -> 课程:数学, 英语 课程:数学 -> 学生:张三, 李四
5:Mybatis映射区别
关系类型 | MyBatis 标签 | 描述 | 示例 |
---|---|---|---|
一对一 | <association> | 一个实体与另一个实体唯一关联 | 用户与用户详情 |
一对多 | <collection> | 一个实体与多个实体关联 | 用户与订单、部门与员工 |
多对多 | <collection> | 通过中间表关联多个实体 | 学生与课程、用户与角色 |
- 一对一使用
<association>
,因为关联的对象是一个单一的实体。- 一对多和多对多使用
<collection>
,因为关联的对象是一个集合。- 多对多需要通过中间表进行关联,这与一对多的区别在于 SQL 中的表连接复杂度。