Mybatis 学习(五)——延迟加载与分步查询


本篇博客主要讲的是延迟加载,也叫懒加载,但是懒加载往往与分布查询同时使用,作为背景知识我们也介绍一下分布查询

一、分步查询

分布查询通常应用于关联表查询,通常我们关联查询是进行多表联合查询,分布查询时先查询主表,然后通过主表得到的信息将参数传递给关联表,查询关联表的信息。
从代码层面上来说:
关联表能简化代码编写逻辑,减小代码编写难度
从功能层面上来说:关联表只需要查询一次数据库,对于业务量小的系统来说效率更高,数据库压力更小

分布查询对染需要多次查询数据,但是这也意味着能够更好的使用数据缓存服务,且缓存的数据耦合度低,利用率高,单词查询效率很高,对于业务量大的系统来说数据库压力较小

分布查询的实现
需求:通过分布查询查询学生信息
下面这两个类是我们今天使用的例子,Student 类里面有一个Dept 的对象,我们通过分布查询来得到学生的信息。

public class Student {
    private Integer id;
    private String name;
    private String passward;
    private Dept  dept;

    public Student(){

    }
    public Student(Integer id ,String name,String passward) {
        this.id = id;
        this.name = name;
        this.passward = passward;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public Student(Integer id , String name, String passward, Dept dept) {
        this.id = id;
        this.name = name;
        this.passward = passward;
        this.dept = dept;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDid(Dept dept) {
        this.dept = dept;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPassward() {
        return passward;
}

    public void setPassward(String passward) {
        this.passward = passward;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", passward='" + passward + '\'' +
                '}';
    }

public class Dept {
    private Integer id;
    private String name;
    private List<Student> stus;
    public Dept(){}

    public Dept(Integer id,String name) {
        this.id = id;
        this.name = name;
    }
    public Dept(Integer id){
        this.id = id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<Student> getStus() {
        return stus;
    }

    public void setStus(List<Student> stus) {
        this.stus = stus;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    @Override
    public String toString() {
        return "Dept{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

第一步:我们在dao层定义两个接口

/**
    * 通过id查学生信息,分步查询
    * @param id
    * @return
    */
   public Student getStuByIdStep(Integer id);
   /**
     * 通过id查出Dept 信息
     * @param id
     * @return
     */
    public Dept getDeptByIdPlus(Integer id);

第二步:编写对应的映射文件

<resultMap id="MystudentStep" type="com.tulun.bean.Student">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>
        <result column="passward" property="passward"></result>
        <!--
            association:定义关联对象的封装规则
            select:表明当前属性是调用select 指定的方法查出的结果
            column:指定将哪一列的值传给这个方法
            流程:使用select 指定的方法(传入column 指定的这列参数的值)查出对象,
                    并封装给property 指定的属性
        -->
        <association property="dept"
                     select="com.tulun.dao.DeptMapper.getDeptById"
                     column="d_id">
        </association>
    </resultMap>

解释一下association 里面的属性

属性 作用
select 表示当前是调用select 指定的方法查询结果
property 将select 查询得到的结果封装给主表的哪个属性
column 将主表的哪一列传给这个属性

流程:使用select 指定的方法,传入的参数是column指定的参数,将查询的结果封装给property 指定的属性

第三步:编写查询的SQL文件

 <select id="getStuByIdStep" resultMap="MystudentStep">
            select * from student where id = #{id}
</select>
<select id="getDeptById" resultType="com.tulun.bean.Dept">
     select * from dept where id = #{id}
</select>

第四步:单元测试

@Test
   public void stepTest(){
       StudentMapperPlus mapper = session.getMapper(StudentMapperPlus.class);
       Student stu = mapper.getStuByIdStep(1);
   }

在这里插入图片描述
从打印的日志可以看出和关联查询不同的是这里发送了两条SQL语句到数据库
我们总结一下整个过程

  • 通过我们传入的id查询主表(Student)
  • 主表哦查询的信息有一列是d_id ,表示的是部门id,把这个d_id 传入关联表(Dpet),得到关联的对象的信息

二、延时加载

MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效的减少数据库压力。

Mybatis 根据关联对象查询Select 语句的查询时机分为直接加载、侵入式加载、深度延迟性加载

1.直接加载

执行完主加载对象的select语句,马上执行关联对象的Select语句

2.侵入式加载

执行完主加载对象查询后不会马上执行关联对象查询,但是当访问主加载对象时,就会加载关联对象的查询。即对关联对象的查询执行,侵入到了主加载对象的详情访问中。也可以这样理解:将关联对象的详情侵入到了主加载对象的详情中,即将关联对象的详情作为主加载对象的详情的一部分出现了。

深度延迟加载

执行主对象的查询时不会执行关联对象的执行,访问主对象详情时也不会执行关联对象的查询,只有当访问关联对象时才会对其进行查询

上面那个例子中,我们有时候暂时不需要dept 的信息,或者根本就不需要dept的信息,但是按照原来的方法也就是立即加载,也就是直接加载

这三种加载方式的切换只要设置配置文件的两个属性就好

直接加载
配置文件

		<!-- 延时加载 -->
        <setting name="lazyLoadingEnabled" value="false"/>
        <!--侵入式加载-->
        <setting name="aggressiveLazyLoading" value="false"/>

注意:当lazyLoadingEnabled 设置为false ,aggressiveLazyLoading 是不起作用的

 @Test
   public void stepTest(){
       StudentMapperPlus mapper = session.getMapper(StudentMapperPlus.class);
       Student stu = mapper.getStuByIdStep(1);
    
   }

在这里插入图片描述
侵入式加载
侵入式加载分为两种情况
设置配置文件

	<!-- 延时加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--侵入式加载-->
        <setting name="aggressiveLazyLoading" value="true"/>

1.当我们不访问主对象时
在这里插入图片描述
2.当我们访问主对象时

@Test
   public void stepTest(){
       StudentMapperPlus mapper = session.getMapper(StudentMapperPlus.class);
       Student stu = mapper.getStuByIdStep(1);
       System.out.println(stu);
   }

访问主对象的时候可以看到关联对象查询也被执行
在这里插入图片描述
深度延迟加载

设置配置文件

		<!-- 延时加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--侵入式加载-->
        <setting name="aggressiveLazyLoading" value="false"/>

1.当不访问关联对象,仅仅访问主对象,关联对象的查询不被执行

 @Test
   public void stepTest(){
       StudentMapperPlus mapper = session.getMapper(StudentMapperPlus.class);
       Student stu = mapper.getStuByIdStep(1);
       System.out.println(stu);
   }

在这里插入图片描述
2.当访问关联对象的时候,关联对象的查询才会被执行

 @Test
   public void stepTest(){
       StudentMapperPlus mapper = session.getMapper(StudentMapperPlus.class);
       Student stu = mapper.getStuByIdStep(1);
	   System.out.println(stu.getDept());
   }

访问了两次数据库
在这里插入图片描述
fetchType 参数

 <association property="dept"
                     fetchType="lazy"
                     select="com.tulun.dao.DeptMapper.getDeptById"
                     column="d_id">
        </association>

fetchType是association 下的一个子参数,局部方法可知指定加载形式,是懒加载还是积极加载它有值可以为lazy 或者是eager,lazy 表示懒加载,eager 表示延迟加载。

当设置了fetchType参数以后,以这个参数为标准,全局配置的不起作用

猜你喜欢

转载自blog.csdn.net/Alyson_jm/article/details/92393301