Mybatis queries delay loading details and instances, and mybatis details

Source: Internet
Author: User

Mybatis queries delay loading details and instances, and mybatis details

Detailed description of Mybatis query delay loading and Examples

1.1 enable delayed Loading

The delayed loading of Mybatis is for nested queries. It refers to querying only the outermost layer of SQL statements during queries. The inner layer of SQL statements will be queried only when needed. By default, delayed loading of Mybatis is disabled. That is, all nested SQL statements are checked and all object information is queried.There are two ways to enable delayed loading.

The first is to specify the fetchType attribute value as "lazy" on the corresponding <collection> or <association> label ". In the following example, BaseResultMap is returned when the query id is selectByPrimaryKey. In BaseResultMap, we specify the attribute "nodes" as a set type, in addition, the query id is selectNodes. we specify the fetchType of the query as lazy, that is, delayed loading.

  <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>

The second is to enable global delayed loading. You can enable global delayed loading by adding the following configuration under the <settings> Tab Of The Mybatis configuration file. After global delayed loading is enabled, we do not need to configure delayed loading on each nested subquery. If a nested subquery does not need to be loaded, you can set its fetchType = "eager ". The fetchType set on the nested query can overwrite the global delayed loading settings.

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

1.2 Analysis

The query result of Mybatis is processed by the handleResultSets () method of the ResultSetHandler interface. The ResultSetHandler interface has only one implementation, DefaultResultSetHandler. If you are interested, you can take a look at its source code and how it processes the result set. For the topic of this article, the core method of delayed loading is as follows.

 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; }

In the above method, we can see that Mybatis first creates an object of the return type according to the normal situation. When our ResultMap contains a subquery, it will create the corresponding proxy object based on the normal returned type object. Yes, you are not mistaken, that is, our direct result is a proxy object, rather than the attribute corresponding to the subquery is a proxy object. By default, it is a proxy object created based on the sistproxyfactory class. You can change it through the global configuration proxyFactory of Mybatis. The optional values are CGLIB and ipvsist. The default value is the latter. Add the CGLIB package when using the CGLIB proxy.

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

Looking back at our previous delayed loading configuration, one of our queries returns a SysWfProcess-type object, which has a nodes attribute of the SysWfNode set type, the nodes attribute is found through a subquery and is delayed loading. In this case, we will perform the following tests.

 @Test  public void testLazyLoad1() {   SysWfProcessMapper mapper = this.session.getMapper(SysWfProcessMapper.class);   SysWfProcess process = mapper.selectByPrimaryKey(1);   System.out.println(process.getClass());  } 

At this time, you will find that the output result of the above test code is a proxy class, rather than our own com. elim. learn. mybatis. model. SysWfProcess type. In addition, if you enable log output and print the DEBUG log, you will see that Mybatis sends two SQL statements for query.

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: 1class com.elim.learn.mybatis.model.SysWfProcess_$$_jvstc25_02016-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 

However, if we put the last System. out. println () is removed, that is to say, we only query the SysWfProcess object from the database. If we do not use it, you will find that Mybatis only sends one SQL statement by viewing the log output, that is, only the information of SysWfProcess is queried. Why?

1.3 aggressiveLazyLoading

This is because when we enable delayed loading, our query results return a proxy object. When we access the method of this proxy object, all objects with delayed loading will be loaded. This can be a good explanation of the above scenario. However, if this is the case, it seems that the delay loading of Mybatis is of little effect. But this is not the case. This is only a default policy of Mybatis. We can change it through the global configuration of Mybatis aggressiveLazyLoading. The default value is true, this indicates that during Delayed loading, all delayed loading objects will be loaded when the method of accessing the proxy object for the first time. When it is set to false, the corresponding data will be loaded from the database only when we first access objects with delayed loading. Note that before the delayed object is loaded from the database, the attribute of the corresponding delayed object will be null, because you didn't assign a value to it.

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

1.4 lazyLoadTriggerMethods

What if we set aggressiveLazyLoading = "false" but want to load all the delayed objects from the database before calling some methods? In this case, you can use the lazyLoadTriggerMethods parameter to specify the method call for loading the delayed object. The default values are equals, clone, hashCode, and toString. That is to say, we will load delayed loading objects from the database before calling these methods of proxy objects.

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

Mybatis delays loading the Agent process of the generated proxy object. You can refer to the process of creating a proxy object in ProxyFactory. The following is the Agent process of the proxy object created based on ipvsist, CGLIB-based proxy is similar. From the following code, we can see that the proxy object of Mybatis needs to load the delayed object from the database before the target method is called, this ensures that the objects that are delayed to be loaded when our target method is called have been loaded from the database.

@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);   }  } }

This article describes the association based on <collection>. In fact, the delayed loading of the objects associated with <association> is the same, and their default policies are the same.

Thank you for reading this article. I hope it will help you. Thank you for your support for this site!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.