目录
引入
前面文章的动态sql和注解开发大都围绕一张表的增删改查展开,接下来引入关联映射,关联映射主要用于处理多张表之间关系,包括且不限于一对一、多对一、多对多等。接下来就从这三个角度切入。
一、创建表结构
首先在数据库创建要操作的表:
1.学生表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
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;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '张三', '男', 18, 1);
INSERT INTO `student` VALUES (2, '李四', '女', 18, 1);
INSERT INTO `student` VALUES (3, '王五', '男', 18, 1);
INSERT INTO `student` VALUES (4, '小白', '女', 18, 1);
INSERT INTO `student` VALUES (5, '小黑', '男', 18, 1);
INSERT INTO `student` VALUES (6, '小红', '女', 20, 2);
INSERT INTO `student` VALUES (7, '小李', '男', 20, 2);
INSERT INTO `student` VALUES (8, '小张', '女', 20, 2);
INSERT INTO `student` VALUES (9, '小赵', '男', 20, 2);
INSERT INTO `student` VALUES (10, '小王', '女', 20, 2);
SET FOREIGN_KEY_CHECKS = 1;
2.老师表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for teacher
-- ----------------------------
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;
-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES (1, '张老师');
INSERT INTO `teacher` VALUES (2, '李老师');
SET FOREIGN_KEY_CHECKS = 1;
二、查询学生对应的老师
1.第一种形式 连表查询
SELECT student.id,student.name,teacher.name FROM student LEFT JOIN teacher on student.t_id = teacher.id
①:设置实体类
学生类:
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"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="t_id" column="t_id"/>
<!-- 复杂的属性我们需要单独去处理 对象:association 集合:collection -->
<!-- property="teacher" student类当中的关联字段 -->
<!-- javaType="com.javen.model.Teacher" 为复杂属性设置类类型-->
<association property="teacher" javaType="com.qcby.entity.Teacher">
<result property="id" column="id"/>
<result property="Tname" column="Tname"/>
</association>
</resultMap>
2.第二种形式 分步查询(分段查询--支持懒加载)
SELECT s.id,s.Sname,t.Tname FROM student s,teacher t where s.t_id = t.id
①:设置实体类
这里的实体类不需要变动(还是单纯对应数据库表项即可),即:
学生类:
public class Student {
private Integer id;
private String Sname;
private String sex;
private Integer age;
private Integer t_id;
}
老师类:
public class Teacher {
private Integer id;
private String Tname;
}
②:查询语句
学生xml查询中:
<select id = "getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<!--结果映射集-->
<resultMap id="StudentTeacher" type="com.qcby.entity.Student">
<result property="id" column="id"/>
<result property="Sname" column="Sname"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="t_id" column="t_id"/>
<!-- select="getTeacher" :调用下一个查询语句 -->
<!-- column="t_id" 两个表的关联字段-->
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher" select="com.qcby.dao.TeacherDao.getTeacher"/>
</resultMap>
老师xml中:
<select id="getTeacher" resultType="com.qcby.entity.Teacher">
select * from teacher where id = #{t_id}; <!-- #{id}; 可以写任何东西,因为会自动匹配 t_id -->
</select>
三、查询教师的学生(一对多)
1.第一种形式:按照结果嵌套处理
SELECT teacher.id,teacher.name,student.name FROM teacher LEFT JOIN student on student.t_id = teacher.id
①.设置实体类
学生类:
public class Student {
private Integer id;
private String Sname;
private String sex;
private Integer age;
private Integer t_id;
}
老师类:
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">
<result property="id" column="id"/>
<result property="Tname" column="Tname"/>
<!-- 复杂的属性我么需要单独去处理 对象:association 集合:collection
在集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="com.qcby.entity.Student">
<result property="Sname" column="Sname"/>
</collection>
</resultMap>
2.第二种形式:按照查询嵌套处理(分段处理--支持懒加载)
SELECT s.id,s.Sname,t.Tname FROM student s,teacher t where s.t_id = t.id
①.设置实体类
这里实体学生类和老师类只要简单对应数据库表项就好,不用额外加东西。
②.查询语句
老师xml:
<!--按照查询嵌套处理-->
<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="com.qcby.dao.StudentDao.getStudentByTeacherId" />
</resultMap>
学生xml:
<select id="getStudentByTeacherId" resultType="com.qcby.entity.Student">
select * from student where t_id = #{t_id}
</select>
四、MyBatis延迟加载策略
以上有两种写法来表示查询信息,分别是链表查询和分步查询的方法。那么既然我么能用一个SQL语句能够执行完,那为什么还要分开来写呢?
原因很简单:同学们可以发现如果我们把他们连在一起那么他们就是一个多表查询语句,如果不放在一起执行,那那就是单独一个表的查询语句。但是这需要我们设置mybatis的延迟加载(懒加载)
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoding:当开启时,任何方式的调用都会加载该对象的所有属性。否则,该属性会按需加载
此时就可以实现按需加载,需要获取的数据是什么,就只会执行相应的sql.此时会通过association和collection中的fetchType属性设置当前的分步查询是否使用懒加载
fetchType=“lazy(延迟加载) | eager(立即加载)”
1.在主配置文件当中设置延迟加载(懒加载)
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2.在studentDao.xml当中设置分步查询
<select id = "getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<!--结果映射集-->
<resultMap id="StudentTeacher" type="com.qcby.entity.Student">
<result property="id" column="id"/>
<result property="Sname" column="Sname"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="t_id" column="t_id"/>
<!-- select="getTeacher" :调用下一个查询语句 -->
<!-- select="com.qcby.dao.TeacherDao.getTeacher" :调用下一个查询语句 -->
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher"
select="com.qcby.dao.TeacherDao.getTeacher" fetchType="lazy"/>
</resultMap>
3.在TeacherDao.xml当中设置关于教师的查询
<select id="getTeacher" resultType="com.qcby.entity.Teacher" parameterType="java.lang.Integer">
select * from teacher where id = #{t_id}; <!-- #{id}; 可以写任何东西,因为会自动匹配 t_id -->
</select>
4.配置TeacherDao
Teacher getTeacher(Integer id);
5.访问设置
①:只访问student当中的内容
@Test
public void getStudent(){
List<Student> student = mapper.getStudent();
for (Student student1:student) {
System.out.println(student1.getSex());
}
}
②:访问全部的内容和有关Teacher表当中的内容时
@Test
public void getStudent(){
List<Student> student = mapper.getStudent();
for (Student student1:student) {
// System.out.println(student1);
System.out.println(student1.getTeacher().getTname());
}
}
6.一些特殊情况下的查询
我们在主配置文件当中设置的懒加载,对于任何一个分步查询都是有效的,但是在一些特殊的情况下,我们希望有些语句不分开查询,这个时候我们就需要设置该语句只能立即加载
<select id = "getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<!--结果映射集-->
<resultMap id="StudentTeacher" type="com.qcby.entity.Student">
<result property="id" column="id"/>
<result property="Sname" column="Sname"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="t_id" column="t_id"/>
<!-- select="com.qcby.dao.TeacherDao.getTeacher" :调用下一个查询语句 -->
<!-- column="t_id" 两个表的关联字段-->
<!--fetchType="eager" 立即加载-->
<association property="teacher" column="t_id" javaType="com.qcby.entity.Teacher"
select="com.qcby.dao.TeacherDao.getTeacher" fetchType="eager"/>
</resultMap>
测试语句:
@Test
public void getStudent(){
List<Student> student = mapper.getStudent();
for (Student student1:student) {
System.out.println(student1.getSex());
}
}
通过上面两个例子也能看出,所谓的懒加载,就是按需加载。
五、练习
有了上述一对一、一对一和懒加载的概念后,接下来引进一个多对多懒加载的例子:
1.数据库要求(三张表)
- 班级
- 教师
- 教师和班级多对多
来实现多对多返回教师的授课班级信息和班级对应教师信息(分别用合并和分段--分段的情况实现懒加载来写:)
数据库:
班级表(newclass):
教师表(newteacher):
关系表:
2.查询老师对应的班级信息:
① 不分段
老师xml
<!-- ① 返回所有授课信息——不支持懒加载(同时被加载,未分段) -->
<select id="findClass" resultMap="TeacherClass">
select newteacher.*,newclass.*
from newclass
inner join relationship on newclass.cnum = relationship.cnum
inner join newteacher on newteacher.tid = relationship.tid
</select>
<!-- 映射集 -->
<resultMap id="TeacherClass" type="com.my.entity.NewTeacher">
<result column="tid" property="tid"/>
<result column="tname" property="tname"/>
<result column="sex" property="sex"/>
<result column="time" property="time"/>
<collection property="classes" ofType="com.my.entity.NewClass">
<result column="cnum" property="cnum"/>
<result column="note" property="note"/>
</collection>
</resultMap>
实体类需要部分修改,对应二-1.①类型,Dao、Test文件不做过多赘述;
②分段写法
老师xml:
<!-- ②返回所有授课信息——懒加载(分段处理) -->
<!--分段-->
<select id="findClassLazy" resultMap="TeacherClassLazy">
select* from newteacher;
</select>
<!-- 映射集 -->
<resultMap id="TeacherClassLazy" type="com.my.entity.NewTeacher">
<result column="tid" property="tid"/>
<result column="tname" property="tname"/>
<result column="sex" property="sex"/>
<result column="time" property="time"/>
<collection property="classes" column="tid" ofType="com.my.entity.NewClass" select="com.my.dao.ClassDao.classLazyId" fetchType="lazy"/>
</resultMap>
<!--结束-->
班级xml:
<!-- 懒加载给Teacher查询班级信息 -->
<select id="classLazyId" resultType="com.my.entity.NewClass" parameterType="int">
select newclass.cnum,newclass.note,newclass.time
from newclass
left join relationship on newclass.cnum=relationship.cnum
where relationship.tid=#{tid};
</select>
其中对应的Dao、Test不做过多赘述;
3.查询班级对应的老师信息
同上述过程,不做过多赘述。
标签:private,查询,---,teacher,详解,student,MyBatis,id,加载 From: https://blog.csdn.net/m0_74977981/article/details/144487758