MyBatis 关联映射详解
目录
一、创建表结构
1. 学生表 (student)
2. 教师表 (teacher)
二、一对一 & 多对一 关系映射
1. 连表查询(直接查询)
2. 分步查询(懒加载)
三、一对多 关系映射
1. 直接查询
2. 分步查询
四、MyBatis 延迟加载(懒加载)
1. 配置全局懒加载
2. 配置分步查询的懒加载
3. 测试代码
4. 强制立即加载(eager)
一、创建表结构
在 MyBatis 进行关联映射时,我们需要创建 student
(学生表)和 teacher
(教师表),并建立它们之间的关联。
1. 学生表 (student
)
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Sname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`t_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `student` VALUES (1, '张三', '男', 18, 1);
INSERT INTO `student` VALUES (2, '李四', '女', 18, 1);
...
SET FOREIGN_KEY_CHECKS = 1;
2. 教师表 (teacher
)
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Tname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `teacher` VALUES (1, '张老师');
INSERT INTO `teacher` VALUES (2, '李老师');
SET FOREIGN_KEY_CHECKS = 1;
二、一对一 & 多对一 关系映射
1. 连表查询(直接查询)
实体类
public class Student {
private Integer id;
private String Sname;
private String sex;
private Integer age;
private Integer t_id;
private Teacher teacher; // 关联的教师对象
}
public class Teacher {
private Integer id;
private String Tname;
}
查询语句
<select id="getStudent1" resultMap="StudentTeacher1">
SELECT student.id, student.Sname, teacher.Tname
FROM student
LEFT JOIN teacher ON student.t_id = teacher.id
</select>
<resultMap id="StudentTeacher1" type="com.qcby.entity.Student">
<result property="id" column="id"/>
<result property="Sname" column="Sname"/>
<association property="teacher" javaType="com.qcby.entity.Teacher">
<result property="id" column="id"/>
<result property="Tname" column="Tname"/>
</association>
</resultMap>
2. 分步查询(懒加载)
<select id="getStudent" resultMap="StudentTeacher">
SELECT * FROM student;
</select>
<resultMap id="StudentTeacher" type="com.qcby.entity.Student">
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.qcby.entity.Teacher">
SELECT * FROM teacher WHERE id = #{t_id};
</select>
三、一对多 关系映射
1. 直接查询
实体类
public class Teacher {
private Integer id;
private String Tname;
private List<Student> students; // 一个老师有多个学生
}
查询语句
<select id="getTeacher" resultMap="TeacherStudent">
SELECT teacher.id, teacher.Tname, student.Sname
FROM teacher
LEFT JOIN student ON student.t_id = teacher.id;
</select>
<resultMap id="TeacherStudent" type="com.qcby.entity.Teacher">
<collection property="students" ofType="com.qcby.entity.Student">
<result property="Sname" column="Sname"/>
</collection>
</resultMap>
2. 分步查询
<select id="getTeacher" resultMap="TeacherStudent2">
SELECT * FROM teacher;
</select>
<resultMap id="TeacherStudent2" type="com.qcby.entity.Teacher">
<collection property="students" column="id" ofType="com.qcby.entity.Student" select="getStudentByTeacherId" />
</resultMap>
<select id="getStudentByTeacherId" resultType="com.qcby.entity.Student">
SELECT * FROM student WHERE t_id = #{t_id};
</select>
四、MyBatis 延迟加载(懒加载)
1. 配置全局懒加载
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2. 配置分步查询的懒加载
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher"
select="com.qcby.dao.TeacherDao.getTeacher" fetchType="lazy"/>
3. 测试代码
@Test
public void getStudent() {
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student.getSex());
}
}
@Test
public void getStudentWithTeacher() {
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student.getTeacher().getTname());
}
}
4. 强制立即加载(eager)
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher"
select="com.qcby.dao.TeacherDao.getTeacher" fetchType="eager"/>
五、总结
- 一对一 & 多对一 可以使用 连表查询 或 分步查询(懒加载)。
- 一对多 关系可以使用 结果嵌套 或 查询嵌套。
- 懒加载 需要在 MyBatis 配置文件 和 映射 XML 里配置。
- 某些查询可以强制使用立即加载(eager),避免不必要的多次查询。