首页 > 其他分享 >MyBatis详解---关联映射

MyBatis详解---关联映射

时间:2024-12-15 18:30:11浏览次数:6  
标签:private 查询 --- teacher 详解 student MyBatis id 加载

目录

引入

一、创建表结构

1.学生表

2.老师表

二、查询学生对应的老师

1.第一种形式 连表查询

 ①:设置实体类

②:查询语句

2.第二种形式 分步查询(分段查询--支持懒加载)

①:设置实体类

②:查询语句

三、查询教师的学生(一对多)

1.第一种形式:按照结果嵌套处理

 ①.设置实体类

②.查询语句

2.第二种形式:按照查询嵌套处理(分段处理--支持懒加载)

①.设置实体类

②.查询语句

四、MyBatis延迟加载策略

1.在主配置文件当中设置延迟加载(懒加载)

2.在studentDao.xml当中设置分步查询

3.在TeacherDao.xml当中设置关于教师的查询

4.配置TeacherDao

5.访问设置

①:只访问student当中的内容

②:访问全部的内容和有关Teacher表当中的内容时

6.一些特殊情况下的查询

五、练习

1.数据库要求(三张表)

数据库:

2.查询老师对应的班级信息:

① 不分段

②分段写法

3.查询班级对应的老师信息


引入

前面文章的动态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

相关文章

  • 渗透测试-前端加密之AES加密下的SQL注入
    本文是高级前端加解密与验签实战的第4篇文章,本系列文章实验靶场为Yakit里自带的Vulinbox靶场,本文讲述的是绕过前端AES加密进行SQL注入。CryptoJS.AES-被前端加密的SQL注入绕过SQL注入前端代码和上文一样,都是通过AES加密请求的数据。在yaklang\common\vulinbox\db.go中可以看......
  • 2024-2025-1 20241314 《计算机基础与程序设计》第十二周学习总结
    2024-2025-120241314《计算机基础与程序设计》第十二周学习总结作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里2024-2025-1计算机基础与程序设计第十二周作业这个作业的目标复习作业正文正文教材学习内容总结引......
  • NAS部署quark-auto-save,实现网盘资源自由
    安装拉取镜像dockerpullcp0204/quark-auto-save:latest一键运行容器dockerrun-d--namequark-auto-save-p5005:5005-eTZ=Asia/Shanghai-v/volume1/docker/quark-auto-save:/app/config#配置文件路径--restartunless-stoppedcp0204/quark-auto-save......
  • NAS部署quark-auto-save,实现网盘资源自由
    安装拉取镜像dockerpullcp0204/quark-auto-save:latest一键运行容器dockerrun-d--namequark-auto-save-p5005:5005-eTZ=Asia/Shanghai-v/volume1/docker/quark-auto-save:/app/config#配置文件路径--restartunless-stoppedcp0204/quark-auto-save......
  • 什么是 Write-Ahead Logging (WAL) 技术?它的优点是什么?MySQL 中是否用到了 WAL?
    什么是Write-AheadLogging(WAL)技术?Write-AheadLogging(WAL)是一种用于数据库系统的日志记录技术,它要求在对数据库进行任何修改之前,所有的修改都必须先写入到日志文件中。这样做的目的是为了保证事务的持久性和一致性,确保即使数据库发生崩溃或意外关闭,未完成的事务数据也......
  • 学生成绩管理--Python
    定义学生类Student:(1)定义构造函数,有学号、姓名、三门课成绩,并在此构造函数中计算三门课的平均分。(2)重写方法_lt_(),根据平均成绩排序降序,平均成绩相同,按第一门课成绩降序。(3)重写方法_str_(),设置输出格式,输出数据顺序:学号姓名第一门课成绩第二门课成绩平均成绩......
  • RT-Thread 内核基础
    内核基础本章将介绍RT-Thread内核的基础知识,为后续章节的学习奠定基础。主要内容包括:内核简介、系统启动流程以及内核配置。首先,我们将对RT-Thread内核进行简要介绍,并从软件架构的角度来讲解实时内核的组成和实现。这部分内容旨在帮助初学者了解RT-Thread内核相关......
  • Apache Struts 远程代码执行漏洞(CVE-2024-53677)
       0x01阅读须知        技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均......
  • 抖店工作台客服设置自动回复 - 浏览器插件 vx : llike620
    应用场景主流直播平台后台评论自动回复与循环发送话术某些客服平台网页端咨询消息自动回复功能介绍这是一个电脑端浏览器插件扩展,实现模拟人工收发消息,解放双手,摆脱重复工作利用浏览器多开,可以在一台电脑上运行多个浏览器,每个浏览器登录不同账号,同时运行插件。插件不限制直......
  • 抖店如何设置客服自动回复?- 浏览器插件详细步骤解析- vx : llike620
    应用场景主流直播平台后台评论自动回复与循环发送话术某些客服平台网页端咨询消息自动回复功能介绍这是一个电脑端浏览器插件扩展,实现模拟人工收发消息,解放双手,摆脱重复工作利用浏览器多开,可以在一台电脑上运行多个浏览器,每个浏览器登录不同账号,同时运行插件。插件不限制直......