MyBatis懒加载(延迟加载)

Posted 肖帆咪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis懒加载(延迟加载)相关的知识,希望对你有一定的参考价值。

懒加载(延迟加载)

需要查询关联信息时,使用 Mybatis 懒加载特性可有效的减少数据库压力,首次查询只查询主表信息,关联表的信息在用户获取时再加载。

Mybatis 一对一关联的 association 和一对多的 collection 可以实现懒加载。懒加载时要使用 resultMap,不能使用 resultType。

启动懒加载
Mybatis 默认没有打开懒加载配置,需要在 SqlMapperConfig.xml 中通过settings 配置 lazyLoadingEnabled 来开启懒加载。

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

我们建立一个实例来体现懒加载,体现懒加载的优势
创建一个方法用来创建SqlSessionFactory负责创建每次会话

package com.util;

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 java.io.IOException;
import java.io.InputStream;

public class SqlSessionUtil {
    static SqlSessionFactory sqlSessionFactory;

    static {
        //读取mybatis配置文件信息

        try {
           InputStream in = Resources.getResourceAsStream("myBatis-configer.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

        } catch (IOException e) {
            e.printStackTrace();
        }
        //创建SqlSessionFactory负责创建每次会话的sqlSession==connection
        //创建开销比较大,所以整个应用程序只需要创建一个

    }

    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

我们创建个bean类

package com.pojo;
//一个emp员工类
public class Emp {
    private int id;
    private String name;
    private int age;
    private Dept dept;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dept getDept() {
        return dept;
    }

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

import java.util.List;

public class Dept {
    private int id;
    private String name;
    private List<Emp> empList;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public List<Emp> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Emp> empList) {
        this.empList = empList;
    }
}

empDao接口

package com.dao;

import com.ff.pojo.Emp;
import org.apache.ibatis.annotations.Param;

public interface EmpDao {

    //    延迟加载
    Emp findEmpById1(@Param("id") int id);
}

EmpMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.EmpDao">
 
    <!--	延迟加载-->
    <resultMap id="EmpMap1" type="Emp">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <!--	
			部门延迟加载	
			fetchType="lazy"表明使用懒加载
			Select:指定关联查询懒加载对象的 Mapper Statement ID 为findDeptByID
			column="dept_id":关联查询时将 dept_id 列的值传入 findDeptByID,并将 findDeptByID 查询的结果映射到 Emp 的 dept 属性中
			collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同
		--> 
        <association property="dept" javaType="Dept"
                     select="findDeptById" fetchType="lazy" column="dept_id">
            <id property="id" column="id"></id>
            <result property="name" column="name"></result>
        </association>
    </resultMap>
    <select id="findEmpById1" resultMap="EmpMap1">
        select id,name,age,dept_id,user_id from emp where id = #{id}
    </select>
    <select id="findDeptById" resultType="Dept">
        select id,name from dept where id = #{id}
    </select>

</mapper>
package com.ff.test;

import com.ff.dao.EmpDao;
import com.ff.dao.UserDao;
import com.ff.pojo.Dept;
import com.ff.pojo.Emp;
import com.ff.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class emp {
    @Test
    public void findEmpById() throws IOException {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpDao empDao = sqlSession.getMapper(EmpDao.class);
        empDao.findEmpById(1);
        sqlSession.commit();
        sqlSession.close();
    }
}

非懒加载查询情况

他会将两个表关联查询,所有的信息全部加载出来

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 396883763.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
==>  Preparing: SELECT e.id eId, e.name eName, e.age, d.id dId, d.name dName/*, u.id uId, u.user_name uName*/ FROM emp e LEFT JOIN dept d ON e.dept_id = d.id /*LEFT JOIN USER u ON e.user_id = u.id*/ WHERE e.id = ? 
==> Parameters: 1(Integer)
<==    Columns: eId, eName, age, dId, dName
<==        Row: 1, 小崔, 20, 1, 科技部
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Returned connection 396883763 to pool.

Process finished with exit code 0

懒加载查询情况

我们创建一个test方法,用来调用service中的方法

package com.test;

import com.ff.dao.EmpDao;
import com.ff.pojo.Dept;
import com.ff.pojo.Emp;
import com.ff.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class emp {
   
    @Test
    public void findEmpById() throws IOException {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpDao empDao = sqlSession.getMapper(EmpDao.class);

        //延迟加载
        Emp emp = empDao.findEmpById1(2);
        System.out.println(emp.getName());

        //如果不调用emp中的关于Dept的方法,就不会查询部门信息,只会查询emp的数据库信息
        System.out.println("__________________________________");
        System.out.println(emp.getDept().getName());

        sqlSession.close();
    }
}

运行结果

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 396883763.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
==>  Preparing: select id,name,age,dept_id from emp where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, name, age, dept_id
<==        Row: 1, 小崔, 20, 1
<==      Total: 1
小崔
__________________________________
==>  Preparing: select id,name from dept where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, name
<==        Row: 1, 科技部
<==      Total: 1
科技部
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@17a7f733]
Returned connection 396883763 to pool.

Process finished with exit code 0

我们会发现,只有需要部门信息 的时候他才会查询,两张表上的信息他是分两次查询,这样就减少了数据库的开销

以上是关于MyBatis懒加载(延迟加载)的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis-04 懒加载&缓存&注解开发

mybatis分页插件以及懒加载

Mybatis 延迟加载和缓存机制(一级二级缓存)

MyBatis 懒加载

Mybatis框架-第三篇

MyBatis_延迟加载