06. mybatis 延迟加载

06. mybatis 延迟加载

当使用多表联合查询的时候,mybatis会根据需要查询的信息,判断是否可以开启延迟加载,来提高查询效率。

1、什么是延迟加载?

延迟加载其实就是将数据加载时机推迟,比如推迟嵌套查询的执行时机。在Mybatis中经常用到关联查询,但是并不是任何时候都需要立即返回关联查询结果。比如查询订单信息,并不一定需要及时返回订单对应的产品信息,查询商品分类信息并不一定要及时返回该类别下有哪些产品,这种情况一下需要一种机制,当需要查看时,再执行查询,返回需要的结果集,这种需求在Mybatis中可以使用延迟加载机制来实现。延迟加载可以实现先查询主表,按需实时做关联查询,返回关联表结果集,一定程度上提高了效率。

简而言之:

多表联合查询,根据你需要的结果信息,如果只是想要表1 的信息,那么表2 的查询sql语句就会先不执行。

2、启用延迟加载

Mybatis配置文件中通过两个属性lazyLoadingEnabled和aggressiveLazyLoading来控制延迟加载和按需加载。

lazyLoadingEnabled:是否启用延迟加载,mybatis默认为false,不启用延迟加载。lazyLoadingEnabled属性控制全局是否使用延迟加载,特殊关联关系也可以通过嵌套查询中fetchType属性单独配置(fetchType属性值lazy或者eager)。

aggressiveLazyLoading:是否按需加载属性,默认值false,lazyLoadingEnabled属性启用时只要加载对象,就会加载该对象的所有属性;关闭该属性则会按需加载,即使用到某关联属性时,实时执行嵌套查询加载该属性。

3、xml映射的建立

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">
    
<!--    
    namespace 指向对应接口的类路径    
 -->    

<mapper namespace="com.company.project.dao.EmpDao">
    <!-- 把重复的sql代码可以提炼出来,通过定义别名把sql列名和java属性对应 -->
    <sql id="selectResult">
        e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno,d.DNAME,d.LOC 
    </sql>
    
    
    <!-- 关闭延迟加载 -->
    <resultMap type="EmpPo" id="EmpResult1">
        <id property="empno" column="empno"/>
        <result property="ename"  column="ename"/>
        <result property="job"  column="job"/>
        <result property="mgr"  column="mgr"/>
        <result property="hiredate"  column="hiredate"/>
        <result property="sal"  column="sal"/>
        <result property="comm"  column="comm"/>
        <!-- 
            fetchType属性:lazy 开启延迟加载;eager 关闭延迟加载      
            -->
        <association property="deptPo" javaType="DeptPo" fetchType="eager"
        select="com.company.project.dao.EmpDao.findDeptById" column="deptno">
            
        </association>
    </resultMap>
    
    <!-- 开启延迟加载 -->
    <resultMap type="EmpPo" id="EmpResult2">
        <id property="empno" column="empno"/>
        <result property="ename"  column="ename"/>
        <result property="job"  column="job"/>
        <result property="mgr"  column="mgr"/>
        <result property="hiredate"  column="hiredate"/>
        <result property="sal"  column="sal"/>
        <result property="comm"  column="comm"/>
        <!-- 
            fetchType属性:lazy 开启延迟加载;eager 关闭延迟加载      
            -->
        <association property="deptPo" javaType="DeptPo" fetchType="lazy"
        select="com.company.project.dao.EmpDao.findDeptById" column="deptno">
            
        </association>
    </resultMap>
    
    <!-- 
    非延迟加载:直接将两个关联表的数据全部查询出来
    延迟加载(懒加载):使用某一个数据,才将其查询出来 
    -->
    <select id="findById1" parameterType="int" resultMap="EmpResult1">
        select
            e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno
        from 
            emp e
        where e.empno = #{empno}
    </select>
    
    <select id="findById2" parameterType="int" resultMap="EmpResult2">
        select
            e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno
        from 
            emp e
        where e.empno = #{empno}
    </select>

</mapper>

4、测试

EmpTest.java

package com.company.project.test;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.company.project.Po.EmpPo;
import com.company.project.dao.EmpDao;
import com.company.project.util.MyBatisUtil;

import junit.framework.TestCase;

public class EmpTest extends TestCase {

        //没有开启延迟加载,一次查询会把两个sql语句全部运行
        public void testFindById1() {
        try {
            SqlSession sqlSession = MyBatisUtil.getSqlSession();
            EmpDao empDao = sqlSession.getMapper(EmpDao.class);
            
            EmpPo empPo = empDao.findById3(7369);
            
            System.out.println(empPo.getEname());
            //当用到员工表的部门时,才会执行查询dept的sql语句
            System.out.println(empPo.getDeptPo().getDname());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            MyBatisUtil.closeSession();
        }
    }
    
    //开启延迟加载,会根据需要的结果数据来进行sql语句,如下:第一次只查询了emp表
    public void testFindById2() {
        try {
            SqlSession sqlSession = MyBatisUtil.getSqlSession();
            EmpDao empDao = sqlSession.getMapper(EmpDao.class);
            
            EmpPo empPo = empDao.findById3(7369);
            //只查询emp表
            System.out.println(empPo.getEname());
            //当用到员工表的部门时,才会执行查询dept的sql语句
            System.out.println(empPo.getDeptPo().getDname());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            MyBatisUtil.closeSession();
        }
    }
}

结果:

//没有开启延迟加载,testFindById1()的运行结果
[DEBUG] 2020-06-22 19:58:59,893 ==>  Preparing: select e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno from emp e where e.empno = ? 
[DEBUG] 2020-06-22 19:58:59,930 ==> Parameters: 7369(Integer)
[DEBUG] 2020-06-22 19:58:59,957 ====>  Preparing: select deptno,dname,loc from dept where deptno = ? 
[DEBUG] 2020-06-22 19:58:59,958 ====> Parameters: 20(Integer)
[DEBUG] 2020-06-22 19:58:59,960 <====      Total: 1
[DEBUG] 2020-06-22 19:58:59,962 <==      Total: 1
SMITH
RESEARCH


//开启延迟加载,testFindById2()的运行结果
[DEBUG] 2020-06-22 19:57:36,539 ==>  Preparing: select e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno from emp e where e.empno = ? 
[DEBUG] 2020-06-22 19:57:36,570 ==> Parameters: 7369(Integer)
[DEBUG] 2020-06-22 19:57:36,627 <==      Total: 1
SMITH
[DEBUG] 2020-06-22 19:57:36,631 ==>  Preparing: select deptno,dname,loc from dept where deptno = ? 
[DEBUG] 2020-06-22 19:57:36,632 ==> Parameters: 20(Integer)
[DEBUG] 2020-06-22 19:57:36,634 <==      Total: 1
RESEARCH

根据结果就可以开出开启延迟加载的作用,若开启,会根据需求来判断执行的sql语句,若不开启,则执行所有的sql语句。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容