MyBatis 高级映射与延迟加载(分步查询)的详细内容

2024-06-14 06:04

本文主要是介绍MyBatis 高级映射与延迟加载(分步查询)的详细内容,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. MyBatis 高级映射与延迟加载(分步查询)的详细内容

文章目录

  • 1. MyBatis 高级映射与延迟加载(分步查询)的详细内容
  • 2. 准备工作
  • 3. 多对一 高级映射
    • 3.1 第一种方式:级联属性映射
    • 3.2 第二种方式:association
    • 3.3 第三种方式:分步查询
  • 4. 多对一延迟加载
  • 5. 一对多 高级映射
    • 5.1 第一种方式:collection
    • 5.2 第二种方式:分步查询
  • 6. 一对多延迟加载
  • 7. 多对多 高级映射
  • 8. 总结:
  • 9. 最后:


2. 准备工作

准备数据库表:一个班级对应多个学生。班级表:t_clazz;学生表:t_student

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


pom.xml 文件当中配置相关的依赖的 jar 包如下:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rainbowsea</groupId><artifactId>mybatis-005-crud-blog</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><!--        mybatis 的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version></dependency><!--        mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--        引入 logback的依赖,这个日志框架实现了slf4j 规范--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency></dependencies></project>

配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?><configuration debug="false"><!-- 控制台输出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!--mybatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR --><root level="DEBUG"><appender-ref ref="STDOUT"/><appender-ref ref="FILE"/></root></configuration>

配置 MyBatis 的核心配置文件,

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--  使用 <package>	还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 --><package name="com.rainbowsea.mybatis.pojo"/></typeAliases><environments default="mybatis"><environment id="mybatis"><!--            MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 --><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="MySQL123"/></dataSource></environment></environments><mappers><!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致--><package name="com.rainbowsea.mybatis.mapper"></package></mappers>
</configuration>

3. 多对一 高级映射

多对一的高级映射 多种方式,常见的包括三种:

  • 第一种方式:一条SQL语句,级联属性映射。
  • 第二种方式:一条SQL语句,association。
  • 第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)

在这里插入图片描述

多的的一方是:Student
一的一方是: Clazz

怎么分主表和副表
原则:谁在前看,谁就是主表

多对一:多在前,那么多就是主表,
一对多:一在前,那么一就是主表

对照 t_clazz,t_stu 创建的ORM 映射的 Clazz,Student 类

注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作

建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过

pojo类Student中添加一个属性:Clazz clazz; 表示学生关联的班级对象。

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;/*** 学生信息*/
public class Student {  // Student 是多的一方private Integer sid;private String sname;private Clazz clazz;  // Clazz 是一的一方public Student() {}public Student(Integer sid, String sname, Clazz clazz) {this.sid = sid;this.sname = sname;this.clazz = clazz;}@Overridepublic String toString() {return "Student{" +"sid=" + sid +", sname='" + sname + '\'' +", clazz=" + clazz +'}';}public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Clazz getClazz() {return clazz;}public void setClazz(Clazz clazz) {this.clazz = clazz;}}

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;/*** 多对一*/
public class Clazz {private Integer cid;private String cname;public Clazz() {}public Clazz(Integer cid, String cname) {this.cid = cid;this.cname = cname;}@Overridepublic String toString() {return "Clazz{" +"cid=" + cid +", cname='" + cname + '\'' +'}';}public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}
}

3.1 第一种方式:级联属性映射

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;import com.rainbowsea.mybatis.pojo.Student;import java.util.List;public interface StudentMapper {/*** 根据id获取学生信息,同时获取学生关联的班级信息* @param id 学生的id* @return 学生对象,但是学生对象当中含有班级对象*/Student selectById(Integer id);}

resultMap 标签当中定义POJO类属性 与 数据表字段名映射关系:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper"><resultMap id="studentResultMap" type="Student"><id property="sid" column="sid"></id><result property="sname" column="sname"></result><result property="clazz.cid" column="cid"></result><result property="clazz.cname" column="cname"></result></resultMap><!--	id 要是 namespace 对应接口上的方法名: --><select id="selectById" resultMap="studentResultMap">select s.sid,s.sname,c.cid,c.cnamefrom t_stu sleft join t_clazz c on s.cid = c.cidwhere s.sid = #{sid}</select></mapper>

运行测试:

在这里插入图片描述

package com.rainbowsea.mybatis.test;import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class StudentMapperTest {@Testpublic void testSelectById() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = mapper.selectById(5);System.out.println(student);sqlSession.close();}}

3.2 第二种方式:association

与第一种方式类似,在第一种方式的基础上只需要修改 resultMap 中的配置:association 即可。其他位置都不需要修改。

association翻译为:关联。

学生对象关联一个对象(这里关联班级对象)。

在这里插入图片描述


import com.rainbowsea.mybatis.pojo.Student;import java.util.List;public interface StudentMapper {/*** 一条SQL语句,association* @param id* @return*/Student selectByIdAssociation(Integer id);}
association 翻译为关联,一个student 对象关联一个Clazz对象
property,提供要映射的POJO类的属性名
javaType: 用来指定要映射的Java类(全限定类名,启用了别名可以用别名)

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper"><resultMap id="studentResultMapAssociation" type="Student"><id property="sid" column="sid"></id><result property="sname" column="sname"></result><!--association 翻译为关联,一个student 对象关联一个Clazz对象property,提供要映射的POJO类的属性名javaType: 用来指定要映射的Java类(全限定类名,启用了别名可以用别名)--><!--        <association property="clazz" javaType="com.rainbowsea.mybatis.pojo.Clazz"></association>我们开启的别名机制--><association property="clazz" javaType="Clazz"><id property="cid" column="cid"></id><result property="cname" column="cname"></result></association></resultMap><select id="selectByIdAssociation" resultMap="studentResultMapAssociation">select s.sid,s.sname,c.cid,c.cnamefrom t_stu sleft join t_clazz c on s.cid = c.cidwhere s.sid = #{sid}</select></mapper>

运行测试:

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class StudentMapperTest {@Testpublic void testStudentResultMapAssociation()  throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = mapper.selectByIdAssociation(5);System.out.println(student);sqlSession.close();}}

3.3 第三种方式:分步查询

在这里插入图片描述

分布查询的优点:

  1. 第一:复用性增强,可以重复证明。(大步拆成N多个小碎布,每一个小碎步更加可以重复利用)
  2. 第二:采用这种分步查询,可以充分利用他们的延迟加载/懒加载机制

什么是延迟加载(懒加载),有什么用?

延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询
作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率

在 mybatis 当中怎么开启延迟加载呢?

association标签之哦给你添加 fetchType = “lazy”

注意,默认情况下是没有开启延迟加载的,需要设置,fetchType=“lazy”

这种在association标签中配置fetchType=“lazy” 是局部的设置,只对当前association关联的sql语句起作用,fetchType=“eager” 表示关闭局部的延迟加载

实际的开发中的模式:
把全局的延迟加载打开。
如果某一步不需要使用延迟加载,请设置fetchType=“eager” 即可

在这里插入图片描述


import com.rainbowsea.mybatis.pojo.Student;import java.util.List;public interface StudentMapper {/***分部查询第一步,先根据学生的sid 查询学生的信息* @param id* @return*/Student selectByIdStep1(Integer id);
}

其他位置不需要修改,只需要修改以及添加以下三处:

第一处:association中select位置填写sqlId。sqlId= namespace+id。其中column属性作为这条子sql语句的条件。

在这里插入图片描述

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper"><!--分布查询的优点:第一:复用性增强,可以重复证明。(大步拆成N多个小碎布,每一个小碎步更加可以重复利用)第二:采用这种分步查询,可以充分利用他们的延迟加载/懒加载机制什么是延迟加载(懒加载),有什么用?延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率在mybatis当中怎么开启延迟加载呢?association标签之哦给你添加fetchType="lazy"注意,默认情况下是没有开启延迟加载的,需要设置,fetchType="lazy"这种在association标签中配置fetchType="lazy" 是局部的设置,只对当前association关联的sql语句起作用fetchType="eager" 表示关闭局部的延迟加载实际的开发中的模式:把全局的延迟加载打开。如果某一步不需要使用延迟加载,请设置fetchType="eager" 即可--><!--    两条SQL语句,完成多对一的分布查询--><!--    这里是第一步,根据学生的id查询学生的所有信息,这些信息当中含有班级id(cid)--><!--    type 是Java中的类集合/数组除了Map,存储的元素类型《用全限定类名,启用了别名机制,用别名column 数据库查询的字段名--><resultMap id="studentResulMapByStep" type="Student"><id property="sid" column="sid"></id><result property="sname" column="sname"></result><!--    <association property="clazz(第一步查询的字段名(与第二步关联的字段))" select="这里需要指定另外第二步SQL语句的ID(com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2)"column="cid 第二步SQL语句传的字段信息,查询"></association>--><!--        <association property="clazz" select="com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2"--><!--                     column="cid" fetchType="lazy"></association>      <--><association property="clazz" select="com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2"column="cid" fetchType="lazy"></association><!--一条SQL语句一条 association--></resultMap><select id="selectByIdStep1" resultMap="studentResulMapByStep">select sid, sname, cidfrom t_stuwhere sid = #{sid}</select></mapper>

第二处:在ClazzMapper接口中添加方法

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;import com.rainbowsea.mybatis.pojo.Clazz;public interface ClazzMapper {/*** 多对一:分布查询第二步:根据cid获取班级信息** @param cid* @return*/Clazz selectByIdStep2(Integer cid);}

在这里插入图片描述

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.ClazzMapper"><!--	id 要是 namespace 对应接口上的方法名: --><!--	id 要是 namespace 对应接口上的方法名: --><select id="selectByIdStep2" resultType="Clazz">select cid, cnamefrom t_clazzwhere cid = #{cid}</select></mapper>

运行测试:

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class StudentMapperTest {@Testpublic void testselectByIdStep1()  throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = mapper.selectByIdStep1(5);System.out.println(student);sqlSession.close();}
}

4. 多对一延迟加载

延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询
作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率

要想支持延迟加载,非常简单,只需要在association标签中添加 fetchType=“lazy” 即可。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper"><!--分布查询的优点:第一:复用性增强,可以重复证明。(大步拆成N多个小碎布,每一个小碎步更加可以重复利用)第二:采用这种分步查询,可以充分利用他们的延迟加载/懒加载机制什么是延迟加载(懒加载),有什么用?延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率在mybatis当中怎么开启延迟加载呢?association标签之哦给你添加fetchType="lazy"注意,默认情况下是没有开启延迟加载的,需要设置,fetchType="lazy"这种在association标签中配置fetchType="lazy" 是局部的设置,只对当前association关联的sql语句起作用fetchType="eager" 表示关闭局部的延迟加载实际的开发中的模式:把全局的延迟加载打开。如果某一步不需要使用延迟加载,请设置fetchType="eager" 即可--><!--    两条SQL语句,完成多对一的分布查询--><!--    这里是第一步,根据学生的id查询学生的所有信息,这些信息当中含有班级id(cid)--><!--    type 是Java中的类集合/数组除了Map,存储的元素类型《用全限定类名,启用了别名机制,用别名column 数据库查询的字段名--><resultMap id="studentResulMapByStep" type="Student"><id property="sid" column="sid"></id><result property="sname" column="sname"></result><!--    <association property="clazz(第一步查询的字段名(与第二步关联的字段))" select="这里需要指定另外第二步SQL语句的ID(com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2)"column="cid 第二步SQL语句传的字段信息,查询"></association>--><!--        <association property="clazz" select="com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2"--><!--                     column="cid" fetchType="lazy"></association>      <--><association property="clazz" select="com.rainbowsea.mybatis.mapper.ClazzMapper.selectByIdStep2"column="cid" fetchType="lazy"></association><!--一条SQL语句一条 association--></resultMap><select id="selectByIdStep1" resultMap="studentResulMapByStep">select sid, sname, cidfrom t_stuwhere sid = #{sid}</select></mapper>

我们现在只查询学生名字,修改测试程序:

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class StudentMapperTest {@Testpublic void testSelectByIdStep1() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = mapper.selectByIdStep1(5);System.out.println("学生的姓名: " + student.getSname());sqlSession.close();}
}

如果后续需要使用到学生所在班级的名称,这个时候才会执行关联的sql语句,修改测试程序:
在这里插入图片描述


import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class StudentMapperTest {@Testpublic void testSelectByIdStep1() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = mapper.selectByIdStep1(5);System.out.println("学生的姓名: " + student.getSname());// 到这里之后,想获取班级名字了String cname = student.getClazz().getCname();System.out.println("学生的班级名称:" + cname);sqlSession.close();}
}

通过以上的执行结果可以看到,只有当使用到班级名称之后,才会执行关联的sql语句,这就是延迟加载。

当然上述方式,仅仅只是局部设置的延迟加载(这对当前 association 关联的 SQL 语句起作用,对其他的位置时不起作用的)。association标签添加fetchType=“lazy”
注意,默认情况下是没有开启延迟加载的,需要设置,fetchType=“lazy”
这种在association标签中 配置fetchType=“lazy” 是局部的设置,只对当前association关联的 sql语句起作用
fetchType=“eager” 表示关闭局部的延迟加载

在mybatis中如何开启全局的延迟加载呢 ?需要setting配置,参考 MyBatis 中文开发手册 https://mybatis.net.cn/ 如下:

在这里插入图片描述

<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>

注意:settings 标签的正确位置顺序,可以根据报错信息进行纠正。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings>
<!--        启用驼峰命名映射--><setting name="mapUnderscoreToCamelCase" value="true"/>
<!--       延迟加载的全局开关,默认值是 false 不开启 (简单的说就是:所有只要但凡带有分布的,都采用延迟加载)--><setting name="lazyLoadingEnabled" value="true"/></settings><!--    起别名--><typeAliases><!--  使用 <package>	还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 --><package name="com.rainbowsea.mybatis.pojo"/></typeAliases><environments default="mybatis"><environment id="mybatis"><!--            MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 --><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="MySQL123"/></dataSource></environment></environments><mappers><!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致--><package name="com.rainbowsea.mybatis.mapper"></package></mappers>
</configuration>

把fetchType="lazy"去掉。 测试 全局设置是否有效。

在这里插入图片描述

执行以下程序:

在这里插入图片描述

在这里插入图片描述

通过以上的测试可以看出,我们已经开启了全局延迟加载策略。开启全局延迟加载之后,所有的sql都会支持延迟加载。如果我们想其中的某个SQL 语句你不希望它支持延迟加载怎么办呢?

可以将该SQL 语句的 fetchType 设置为 eager,就不会启用延迟加载机制的。这样的话,针对某个特定的SQL 语句,你就关闭了延迟加载机制。后期我们要不要开启延迟加载机制,主要看实际的业务需求是怎样的。

在这里插入图片描述

运行测试:

在这里插入图片描述

在这里插入图片描述

实际的开发中的模式:把全局的延迟加载打开。如果某一步不需要使用延迟加载,请设置fetchType=“eager” 即可

5. 一对多 高级映射

一对多的实现,通常是在一的一方中有List集合属性。

在 Clazz 类中添加List<Student> stus ; 属性。

在这里插入图片描述

这里的一对多:关系
public class Student{}public class Clazz { // 一个班级对象
// 一个班级对应多个学生
// 怎么去表示这个班级对应了多个学生对象呢
// 集合或者数组都可以容纳多个元素
List<Student> studentList
一对多,一在前,一是主表,多是副表
主表: t_clazz
副表: t_stu
}

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;import java.util.List;/*** 多对一*/
public class Clazz {private Integer cid;private String cname;private List<Student> stus;public Clazz() {}public Clazz(Integer cid, String cname) {this.cid = cid;this.cname = cname;}public Clazz(Integer cid, String cname, List<Student> stus) {this.cid = cid;this.cname = cname;this.stus = stus;}public List<Student> getStus() {return stus;}public void setStus(List<Student> stus) {this.stus = stus;}@Overridepublic String toString() {return "Clazz{" +"cid=" + cid +", cname='" + cname + '\'' +", stus=" + stus +'}';}public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}
}

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;/*** 学生信息*/
public class Student {private Integer sid;private String sname;public Student() {}public Student(Integer sid, String sname) {this.sid = sid;this.sname = sname;}@Overridepublic String toString() {return "Student{" +"sid=" + sid +", sname='" + sname + '\'' +'}';}public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}
}

5.1 第一种方式:collection

**注意:是 collection 不是 association 。 **

如果返回的映射 POJO 类当中有一个集合属性,则用 collection 标签负责处理。

-对多,这里是 collection ,collection 是集合的意思,定义集合/数组当中元素的映射信息(这里是Student 类型的映射)ofType 属性用来指定集合当中的元素类型,全限定类名(启用别名用别名)注意是ofType,表示“集合中的类型”。
<collection property="stus(表示POJo类中的属性)" ofType="Student"></collection>-->

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;import com.rainbowsea.mybatis.pojo.Clazz;public interface ClazzMapper {/*** 根据班级编号查询班级信息* @param cid* @return*/Clazz selectByCollection(Integer cid);
}

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.ClazzMapper"><!--	id 要是 namespace 对应接口上的方法名: --><resultMap id="clazzResultMap" type="Clazz"><id property="cid" column="cid"></id><result property="cname" column="cname"></result><!--        -对多,这里是 collection ,collection 是集合的意思,定义集合/数组当中元素的映射信息(这里是Student 类型的映射)--><!--        ofType 属性用来指定集合当中的元素类型,全限定类名(启用别名用别名)--><!--        <collection property="stus(表示POJo类中的属性)" ofType="Student"></collection>--><collection property="stus" ofType="Student"><id property="sid" column="sid"></id><result property="sname" column="sname"></result></collection></resultMap><select id="selectByCollection" resultMap="clazzResultMap">select c.cid, c.cname, s.sid, s.snamefrom t_clazz cleft join t_stu s on c.cid = s.cidwhere c.cid = #{cid}</select></mapper>

运行测试:

在这里插入图片描述

package com.rainbowsea.mybatis.test;import com.rainbowsea.mybatis.mapper.ClazzMapper;
import com.rainbowsea.mybatis.pojo.Clazz;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class ClazzMapperTest {@Testpublic void testSelectByCollection() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);Clazz clazz = mapper.selectByCollection(1000);System.out.println(clazz);sqlSession.close();}
}

5.2 第二种方式:分步查询

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;import com.rainbowsea.mybatis.pojo.Clazz;public interface ClazzMapper {/*** 分布查询,第一步,根据班级编号获取班级信息* @param cid* @return*/Clazz selectByStep1(Integer cid);}

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;import com.rainbowsea.mybatis.pojo.Student;import java.util.List;public interface StudentMapper {/*** 一对多:根据班级编号查询学生信息*/List<Student> selectByCidsStep2(Integer cid);}

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.ClazzMapper"><!--    分布查询第一步:根据班级的cid获取班级信息--><resultMap id="clazzResultMapStep" type="Clazz"><id property="cid" column="cid"></id><result property="cname" column="cname"></result><collection property="stus"select="com.rainbowsea.mybatis.mapper.StudentMapper.selectByCidsStep2"column="cid"></collection></resultMap><select id="selectByStep1" resultMap="clazzResultMapStep">select cid, cnamefrom t_clazzwhere cid = #{cid}</select></mapper>

在这里插入图片描述

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper"><!--    一对多 ,分布查询第二步--><select id="selectByCidsStep2" resultType="Student">select sid, sname, cidfrom t_stuwhere cid = #{cid}</select></mapper>

运行测试:

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.mybatis.test;import com.rainbowsea.mybatis.mapper.ClazzMapper;
import com.rainbowsea.mybatis.pojo.Clazz;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;public class ClazzMapperTest {@Testpublic void testSelectByStep1() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");SqlSession sqlSession = sqlSessionFactory.openSession();ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);Clazz clazz = mapper.selectByStep1(1000);//System.out.println(clazz);// 只访问班级名字System.out.println(clazz.getCname());// 只有用到的时候才会去执行第二步SQLSystem.out.println(clazz.getStus());sqlSession.close();}}

6. 一对多延迟加载

一对多延迟加载机制和多对一是一样的。同样是通过两种方式:

  • 第一种:fetchType=“lazy”
  • 第二种:修改全局的配置setting,**lazyLoadingEnabled=true,**如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType=“eager”

7. 多对多 高级映射

多对多:分解成两个一对多,然后其中一个是:一对一的关系

8. 总结:

  1. 多对一的高级映射 多种方式,常见的包括三种:
    • 第一种方式:一条SQL语句,级联属性映射。
    • 第二种方式:一条SQL语句,association。
    • 第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)
  2. association翻译为:关联。学生对象关联一个对象(这里关联班级对象)。
  3. 分布查询就是利用延时加载的机制。
  4. 延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询,作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率。
  5. 在association标签中配置fetchType=“lazy” 是局部的设置,只对当前association关联的sql语句起作用,fetchType=“eager” 表示关闭局部的延迟加载。
  6. 如果返回的映射 POJO 类当中有一个集合属性,则用 collection 标签负责处理。
  7. 实际的开发中的模式:把全局的延迟加载打开。如果某一步不需要使用延迟加载,请设置fetchType=“eager” 即可
  8. 多对多:分解成两个一对多,然后其中一个是:一对一的关系

9. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

这篇关于MyBatis 高级映射与延迟加载(分步查询)的详细内容的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1059575

相关文章

房产证 不动产查询

陕西政务服务网(便民服务)陕西政务服务网(手机版?更直观)不动产权证书|不动产登记证明(电子证照)商品房合同备案查询权利人查询

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

VMware9.0详细安装

双击VMware-workstation-full-9.0.0-812388.exe文件: 直接点Next; 这里,我选择了Typical(标准安装)。 因为服务器上只要C盘,所以我选择安装在C盘下的vmware文件夹下面,然后点击Next; 这里我把√取消了,每次启动不检查更新。然后Next; 点击Next; 创建快捷方式等,点击Next; 继续Cont

持久层 技术选型如何决策?JPA,Hibernate,ibatis(mybatis)

转自:http://t.51jdy.cn/thread-259-1-1.html 持久层 是一个项目 后台 最重要的部分。他直接 决定了 数据读写的性能,业务编写的复杂度,数据结构(对象结构)等问题。 因此 架构师在考虑 使用那个持久层框架的时候 要考虑清楚。 选择的 标准: 1,项目的场景。 2,团队的技能掌握情况。 3,开发周期(开发效率)。 传统的 业务系统,通常业

(超详细)YOLOV7改进-Soft-NMS(支持多种IoU变种选择)

1.在until/general.py文件最后加上下面代码 2.在general.py里面找到这代码,修改这两个地方 3.之后直接运行即可

通过高德api查询所有店铺地址信息

通过高德api查询所有店铺地址电话信息 需求:通过高德api查询所有店铺地址信息需求分析具体实现1、申请高德appkey2、下载types city 字典值3、具体代码调用 需求:通过高德api查询所有店铺地址信息 需求分析 查询现有高德api发现现有接口关键字搜索API服务地址: https://developer.amap.com/api/webservice/gui

加载资源文件失败

背景         自己以前装了一个海康的深度学习算法平台,试用期是一个月,过了一个月之后,因为没有有效注册码或者加密狗的支持了导致无法使用,于是打算卸载掉,在卸载一个软件的时候,无论是使用控制面板还是软件自带的卸载功能,总是卸载不掉,提示“加载资源文件失败”。该软体主要包括以下两部分: 用自带卸载功能卸载的时候分别提示如下:     用控制面板卸载的时候反应很慢,最后也是提示这个

vue同页面多路由懒加载-及可能存在问题的解决方式

先上图,再解释 图一是多路由页面,图二是路由文件。从图一可以看出每个router-view对应的name都不一样。从图二可以看出层路由对应的组件加载方式要跟图一中的name相对应,并且图二的路由层在跟图一对应的页面中要加上components层,多一个s结尾,里面的的方法名就是图一路由的name值,里面还可以照样用懒加载的方式。 页面上其他的路由在路由文件中也跟图二是一样的写法。 附送可能存在

Java注解详细总结

什么是注解?         Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。         注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。 自定义注解  现在我们自定义一个MyTest注解 public @interface MyTest{String aaa();boolean bbb()

SQL Server中,查询数据库中有多少个表,以及数据库其余类型数据统计查询

sqlserver查询数据库中有多少个表 sql server 数表:select count(1) from sysobjects where xtype='U'数视图:select count(1) from sysobjects where xtype='V'数存储过程select count(1) from sysobjects where xtype='P' SE