我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Mybatis查询延迟加载的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Mybatis查询延迟加载的示例分析

小编给大家分享一下Mybatis查询延迟加载的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

Mybatis查询延迟加载详解及实例

1.1     启用延迟加载

       Mybatis的延迟加载是针对嵌套查询而言的,是指在进行查询的时候先只查询最外层的SQL,对于内层SQL将在需要使用的时候才查询出来。Mybatis的延迟加载默认是关闭的,即默认是一次就将所有的嵌套SQL一并查了将对象所有的信息都查询出来。开启延迟加载有两种方式。

       第一种是在对应的<collection>或<association>标签上指定fetchType属性值为“lazy”。如下示例中我们在查询id为selectByPrimaryKey的查询时会返回BaseResultMap,在BaseResultMap中,我们指定了属性“nodes”是一个集合类型的,而且是需要通过id为selectNodes的查询进行查询的,我们指定了该查询的fetchType为lazy,即延迟加载。

  <resultMap id="BaseResultMap" type="com.elim.learn.mybatis.model.SysWfProcess">

   <id column="id" jdbcType="INTEGER" property="id" />

   <result column="template_id" jdbcType="INTEGER" property="templateId" />

   <result column="creator" jdbcType="INTEGER" property="creator" />

   <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />

   <collection property="nodes" column="id"

    ofType="com.elim.learn.mybatis.model.SysWfNode" select="selectNodes" fetchType="lazy"/>

  </resultMap>

  <resultMap id="SysWfNodeResult" type="com.elim.learn.mybatis.model.SysWfNode">

   <id column="id" jdbcType="INTEGER" property="nodeId" />

   <result column="process_id" jdbcType="INTEGER" property="processId" />

   <result column="node_code" jdbcType="VARCHAR" property="nodeCode" />

   <result column="node_name" jdbcType="VARCHAR" property="nodeName" />

  </resultMap>

  <select id="selectByPrimaryKey" parameterType="java.lang.Integer"

   resultMap="BaseResultMap">

   select

   <include refid="Base_Column_List" />

   from sys_wf_process

   where id = #{id,jdbcType=INTEGER}

  </select>

  <select id="selectNodes"

   resultMap="SysWfNodeResult">

   select id, process_id, node_code, node_name from sys_wf_node

   where process_id=#{id}

  </select>

       第二种是开启全局的延迟加载。通过在Mybatis的配置文件的<settings>标签下加上如下配置可开启全局的延迟加载。开启了全局的延迟加载后我们就无需再在各个嵌套的子查询上配置延迟加载了,如果有某一个嵌套的子查询是不需要延迟加载的,可以设置其fetchType=”eager”。设置在嵌套查询上的fetchType可以覆盖全局的延迟加载设置。

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

1.2     分析

       Mybatis的查询结果是由ResultSetHandler接口的handleResultSets()方法处理的。ResultSetHandler接口只有一个实现,DefaultResultSetHandler。有兴趣的朋友可以去看一下它的源码,看一下它是如何处理结果集的。对于本文的主题,延迟加载相关的一个核心的方法就是如下这个创建返回结果对象的方法。

 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {

  final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();

  final List<Object> constructorArgs = new ArrayList<Object>();

  final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);

  if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {

   final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();

   for (ResultMapping propertyMapping : propertyMappings) {

    // issue gcode #109 && issue #149

    if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {

     return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);

    }

   }

  }

  return resultObject;

 }

        在上面方法中我们可以看到Mybatis先是根据正常情况创建一个返回类型对应的对象。当我们的ResultMap是包含子查询的时候,其会在我们正常返回类型对象的基础上创建对应的代理对象。对,你没有看错,就是我们的直接结果是代理对象,而不是子查询对应的属性是代理对象。默认是基于JavassistProxyFactory类创建的代理对象。可以通过Mybatis的全局配置proxyFactory来更改,可选值是CGLIB和JAVASSIST,默认是后者。需要使用CGLIB代理时注意加入CGLIB的包。

   <setting name="proxyFactory" value="CGLIB"/>

       回过头来看我们之前的那个延迟加载的配置,我们的一个查询返回的是SysWfProcess类型的对象,其有一个SysWfNode集合类型的nodes属性,nodes属性是通过一个子查询查出来的,而且是延迟加载。这个时候我们来进行以下测试。

 @Test

  public void testLazyLoad1() {

   SysWfProcessMapper mapper = this.session.getMapper(SysWfProcessMapper.class);

   SysWfProcess process = mapper.selectByPrimaryKey(1);

   System.out.println(process.getClass());

  }

       这个时候你会发现,上面的测试代码的输出结果是一个代理类,而不是我们自己的com.elim.learn.mybatis.model.SysWfProcess类型。另外如果你启用了日志输出,并且是打印的DEBUG日志,你会看到Mybatis是发了两条SQL进行查询的。

2016-12-23 15:43:21,131 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: select id, template_id, creator, create_time from sys_wf_process where id = ?

2016-12-23 15:43:21,156 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1(Integer)

2016-12-23 15:43:21,269 DEBUG [main] (BaseJdbcLogger.java:145) - <==   Total: 1

class com.elim.learn.mybatis.model.SysWfProcess_$$_jvstc25_0

2016-12-23 15:43:21,271 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: select id, process_id, node_code, node_name from sys_wf_node where process_id=?

2016-12-23 15:43:21,272 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1(Integer)

2016-12-23 15:43:21,274 DEBUG [main] (BaseJdbcLogger.java:145) - <==   Total: 2

       但是如果我们把最后一个System.out.println()去掉,也就是说我们只是从数据库中查询出SysWfProcess对象,而不使用它的时候,通过查看日志输出你会发现Mybatis又只会发送一条SQL,即只是查询出SysWfProcess的信息。这是为什么呢?

 1.3     aggressiveLazyLoading

       这是因为当我们启用了延迟加载时,我们的查询结果返回的是一个代理对象,当我们访问该代理对象的方法时,都会触发加载所有的延迟加载的对象信息。这也就可以很好的解释上面的场景。但是如果是这样的设计,貌似Mybatis的延迟加载作用不大。但事实并非如此,这只是Mybatis的一个默认策略,我们可以通过Mybatis的全局配置aggressiveLazyLoading来改变它,默认是true,表示延迟加载时将在第一次访问代理对象的方法时就将全部的延迟加载对象加载出来。当设置为false时则会在我们第一次访问延迟加载的对象的时候才会从数据库加载对应的数据。注意在延迟对象未从数据库加载出来前,我们对应延迟对象的属性将是null,因为你没有对它赋值。

  <setting name="aggressiveLazyLoading" value="fasle"/>

1.4     lazyLoadTriggerMethods

       那如果我们设置了aggressiveLazyLoading=”false”,但又希望在调用某些方法之前把所有的延迟对象都从数据库加载出来,怎么办呢?这个时候我们可以通过lazyLoadTriggerMethods参数来指定需要加载延迟对象的方法调用。默认是equals、clone、hashCode和toString,也就是说我们在调用代理对象的这些方法之前就会把延迟加载对象从数据库加载出来。

   <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />

       Mybatis延迟加载生成的代理对象的代理过程,可以参考ProxyFactory的创建代理对象的过程,以下是基于Javassist创建的代理对象的代理过程,基于CGLIB的代理也是类似的。从下面的代码我们可以看到Mybatis的代理对象需要从数据库加载延迟对象时是在目标方法被调用以前发生的,这就可以保证我们的目标方法被调用时延迟加载的对象已经从数据库中加载出来了。

@Override

  public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {

   final String methodName = method.getName();

   try {

    synchronized (lazyLoader) {

     if (WRITE_REPLACE_METHOD.equals(methodName)) {

      Object original = null;

      if (constructorArgTypes.isEmpty()) {

       original = objectFactory.create(type);

      } else {

       original = objectFactory.create(type, constructorArgTypes, constructorArgs);

      }

      PropertyCopier.copyBeanProperties(type, enhanced, original);

      if (lazyLoader.size() > 0) {

       return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);

      } else {

       return original;

      }

     } else {

      if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {

       if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {

        lazyLoader.loadAll();

       } else if (PropertyNamer.isProperty(methodName)) {

        final String property = PropertyNamer.methodToProperty(methodName);

        if (lazyLoader.hasLoader(property)) {

         lazyLoader.load(property);

        }

       }

      }

     }

    }

    return methodProxy.invoke(enhanced, args);

   } catch (Throwable t) {

    throw ExceptionUtil.unwrapThrowable(t);

   }

  }

 }

以上是“Mybatis查询延迟加载的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Mybatis查询延迟加载的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Mybatis延迟加载问题的示例分析

这篇文章主要介绍Mybatis延迟加载问题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!延迟加载问题MyBatis针对关联表中的数据支持延迟加载。延迟加载其实就是将数据加载时机推迟,比如推迟嵌套查询的执行时
2023-06-15

MyBatis流式查询的示例分析

这篇文章主要介绍MyBatis流式查询的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!导读:流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低
2023-06-15

mybatis-plus查询源码的示例分析

这篇文章主要介绍mybatis-plus查询源码的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!配置详情pom.xmldependency> com.baomidou
2023-06-29

计算机网络中网站性能延迟加载图像的示例分析

这篇文章给大家分享的是有关计算机网络中网站性能延迟加载图像的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。由于图片是web上最流行的内容类型之一,因此网站的页面加载时间很容易成为一个问题。即使经过适当的优
2023-06-09

call setlocal中变量延迟的示例分析

这篇文章给大家分享的是有关call setlocal中变量延迟的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。对于批处理新手而言,“变量延迟”这个概念很可能闻所未闻,但是,它却像一堵横亘在你前进道路上的无
2023-06-08

spring中mybatis多表查询处理的示例分析

这篇文章将为大家详细讲解有关spring中mybatis多表查询处理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。package com.swhy.bw.advisor.center.comme
2023-06-02

LINQ查询的示例分析

这篇文章主要介绍LINQ查询的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在之前的C#版中,开发者应用许多不同的查询语言来访问不同的数据源。例如,要查询一个XML文件,开发者会使用XPath,要查询一个SQ
2023-06-17

OJB查询的示例分析

这篇文章主要为大家展示了“OJB查询的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“OJB查询的示例分析”这篇文章吧。OJB查询该文档介绍了不同查询机制的使用。文档中的代码都通过Juni
2023-06-03

Linux服务器高I/O等待延迟问题查找的示例分析

这篇文章主要介绍Linux服务器高I/O等待延迟问题查找的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!0. 首先是top查看一下系统状况 发现两个参数异常,一是平均负载高,一是cpu %wa一直在50%以上
2023-06-16

java类加载的示例分析

这篇文章将为大家详细讲解有关java类加载的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、说明当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过以下三个步骤对该类进行初始化。2、
2023-06-15

java并发中DelayQueue延迟队列原理的示例分析

这篇文章给大家分享的是有关java并发中DelayQueue延迟队列原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。介绍DelayQueue队列是一个延迟队列,DelayQueue中存放的元素必须实现
2023-06-15

Mybatis应用mysql存储过程查询数据的示例分析

小编给大家分享一下Mybatis应用mysql存储过程查询数据的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.创建mysql存储过程,这是个复杂查询加
2023-05-30

编程热搜

目录