Mybatis查询延迟加载详解及实例
<p><strong>Mybatis查询延迟加载详解及实例</strong></p>
<p>
<strong>1.1 启用延迟加载</strong></p>
<p>
Mybatis的延迟加载是针对嵌套查询而言的,是指在进行查询的时候先只查询最外层的SQL,对于内层SQL将在需要使用的时候才查询出来。Mybatis的延迟加载默认是关闭的,即默认是一次就将所有的嵌套SQL一并查了将对象所有的信息都查询出来。<strong>开启延迟加载有两种方式。</strong></p>
<p>
第一种是在对应的<collection>或<association>标签上指定fetchType属性值为“lazy”。如下示例中我们在查询id为selectByPrimaryKey的查询时会返回BaseResultMap,在BaseResultMap中,我们指定了属性“nodes”是一个集合类型的,而且是需要通过id为selectNodes的查询进行查询的,我们指定了该查询的fetchType为lazy,即延迟加载。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_841250">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
<div class="line number16 index15 alt1">
16</div>
<div class="line number17 index16 alt2">
17</div>
<div class="line number18 index17 alt1">
18</div>
<div class="line number19 index18 alt2">
19</div>
<div class="line number20 index19 alt1">
20</div>
<div class="line number21 index20 alt2">
21</div>
<div class="line number22 index21 alt1">
22</div>
<div class="line number23 index22 alt2">
23</div>
<div class="line number24 index23 alt1">
24</div>
<div class="line number25 index24 alt2">
25</div>
<div class="line number26 index25 alt1">
26</div>
<div class="line number27 index26 alt2">
27</div>
<div class="line number28 index27 alt1">
28</div>
<div class="line number29 index28 alt2">
29</div>
<div class="line number30 index29 alt1">
30</div>
<div class="line number31 index30 alt2">
31</div>
<div class="line number32 index31 alt1">
32</div>
<div class="line number33 index32 alt2">
33</div>
<div class="line number34 index33 alt1">
34</div>
<div class="line number35 index34 alt2">
35</div>
<div class="line number36 index35 alt1">
36</div>
<div class="line number37 index36 alt2">
37</div>
<div class="line number38 index37 alt1">
38</div>
<div class="line number39 index38 alt2">
39</div>
<div class="line number40 index39 alt1">
40</div>
<div class="line number41 index40 alt2">
41</div>
<div class="line number42 index41 alt1">
42</div>
<div class="line number43 index42 alt2">
43</div>
<div class="line number44 index43 alt1">
44</div>
<div class="line number45 index44 alt2">
45</div>
<div class="line number46 index45 alt1">
46</div>
<div class="line number47 index46 alt2">
47</div>
<div class="line number48 index47 alt1">
48</div>
<div class="line number49 index48 alt2">
49</div>
<div class="line number50 index49 alt1">
50</div>
<div class="line number51 index50 alt2">
51</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain"><resultMap id=</code><code class="sql string">"BaseResultMap"</code> <code class="sql plain">type=</code><code class="sql string">"com.elim.learn.mybatis.model.SysWfProcess"</code><code class="sql plain">></code>
</div>
<div class="line number2 index1 alt1">
</div>
<div class="line number3 index2 alt2">
<code class="sql spaces"> </code><code class="sql plain"><id </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"id"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"INTEGER"</code> <code class="sql plain">property=</code><code class="sql string">"id"</code> <code class="sql plain">/></code>
</div>
<div class="line number4 index3 alt1">
</div>
<div class="line number5 index4 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"template_id"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"INTEGER"</code> <code class="sql plain">property=</code><code class="sql string">"templateId"</code> <code class="sql plain">/></code>
</div>
<div class="line number6 index5 alt1">
</div>
<div class="line number7 index6 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"creator"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"INTEGER"</code> <code class="sql plain">property=</code><code class="sql string">"creator"</code> <code class="sql plain">/></code>
</div>
<div class="line number8 index7 alt1">
</div>
<div class="line number9 index8 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"create_time"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"TIMESTAMP"</code> <code class="sql plain">property=</code><code class="sql string">"createTime"</code> <code class="sql plain">/></code>
</div>
<div class="line number10 index9 alt1">
</div>
<div class="line number11 index10 alt2">
<code class="sql spaces"> </code><code class="sql plain"><collection property=</code><code class="sql string">"nodes"</code> <code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"id"</code>
</div>
<div class="line number12 index11 alt1">
</div>
<div class="line number13 index12 alt2">
<code class="sql spaces"> </code><code class="sql plain">ofType=</code><code class="sql string">"com.elim.learn.mybatis.model.SysWfNode"</code> <code class="sql keyword">select</code><code class="sql plain">=</code><code class="sql string">"selectNodes"</code> <code class="sql plain">fetchType=</code><code class="sql string">"lazy"</code><code class="sql plain">/></code>
</div>
<div class="line number14 index13 alt1">
</div>
<div class="line number15 index14 alt2">
<code class="sql plain"></resultMap></code>
</div>
<div class="line number16 index15 alt1">
</div>
<div class="line number17 index16 alt2">
<code class="sql plain"><resultMap id=</code><code class="sql string">"SysWfNodeResult"</code> <code class="sql plain">type=</code><code class="sql string">"com.elim.learn.mybatis.model.SysWfNode"</code><code class="sql plain">></code>
</div>
<div class="line number18 index17 alt1">
</div>
<div class="line number19 index18 alt2">
<code class="sql spaces"> </code><code class="sql plain"><id </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"id"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"INTEGER"</code> <code class="sql plain">property=</code><code class="sql string">"nodeId"</code> <code class="sql plain">/></code>
</div>
<div class="line number20 index19 alt1">
</div>
<div class="line number21 index20 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"process_id"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"INTEGER"</code> <code class="sql plain">property=</code><code class="sql string">"processId"</code> <code class="sql plain">/></code>
</div>
<div class="line number22 index21 alt1">
</div>
<div class="line number23 index22 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"node_code"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"VARCHAR"</code> <code class="sql plain">property=</code><code class="sql string">"nodeCode"</code> <code class="sql plain">/></code>
</div>
<div class="line number24 index23 alt1">
</div>
<div class="line number25 index24 alt2">
<code class="sql spaces"> </code><code class="sql plain"><result </code><code class="sql keyword">column</code><code class="sql plain">=</code><code class="sql string">"node_name"</code> <code class="sql plain">jdbcType=</code><code class="sql string">"VARCHAR"</code> <code class="sql plain">property=</code><code class="sql string">"nodeName"</code> <code class="sql plain">/></code>
</div>
<div class="line number26 index25 alt1">
</div>
<div class="line number27 index26 alt2">
<code class="sql plain"></resultMap></code>
</div>
<div class="line number28 index27 alt1">
</div>
<div class="line number29 index28 alt2">
<code class="sql plain"><</code><code class="sql keyword">select</code> <code class="sql plain">id=</code><code class="sql string">"selectByPrimaryKey"</code> <code class="sql plain">parameterType=</code><code class="sql string">"java.lang.Integer"</code>
</div>
<div class="line number30 index29 alt1">
</div>
<div class="line number31 index30 alt2">
<code class="sql spaces"> </code><code class="sql plain">resultMap=</code><code class="sql string">"BaseResultMap"</code><code class="sql plain">></code>
</div>
<div class="line number32 index31 alt1">
</div>
<div class="line number33 index32 alt2">
<code class="sql spaces"> </code><code class="sql keyword">select</code>
</div>
<div class="line number34 index33 alt1">
</div>
<div class="line number35 index34 alt2">
<code class="sql spaces"> </code><code class="sql plain"><include refid=</code><code class="sql string">"Base_Column_List"</code> <code class="sql plain">/></code>
</div>
<div class="line number36 index35 alt1">
</div>
<div class="line number37 index36 alt2">
<code class="sql spaces"> </code><code class="sql keyword">from</code> <code class="sql plain">sys_wf_process</code>
</div>
<div class="line number38 index37 alt1">
</div>
<div class="line number39 index38 alt2">
<code class="sql spaces"> </code><code class="sql keyword">where</code> <code class="sql plain">id = #{id,jdbcType=</code><code class="sql keyword">INTEGER</code><code class="sql plain">}</code>
</div>
<div class="line number40 index39 alt1">
</div>
<div class="line number41 index40 alt2">
<code class="sql plain"></</code><code class="sql keyword">select</code><code class="sql plain">></code>
</div>
<div class="line number42 index41 alt1">
</div>
<div class="line number43 index42 alt2">
<code class="sql plain"><</code><code class="sql keyword">select</code> <code class="sql plain">id=</code><code class="sql string">"selectNodes"</code>
</div>
<div class="line number44 index43 alt1">
</div>
<div class="line number45 index44 alt2">
<code class="sql spaces"> </code><code class="sql plain">resultMap=</code><code class="sql string">"SysWfNodeResult"</code><code class="sql plain">></code>
</div>
<div class="line number46 index45 alt1">
</div>
<div class="line number47 index46 alt2">
<code class="sql spaces"> </code><code class="sql keyword">select</code> <code class="sql plain">id, process_id, node_code, node_name </code><code class="sql keyword">from</code> <code class="sql plain">sys_wf_node</code>
</div>
<div class="line number48 index47 alt1">
</div>
<div class="line number49 index48 alt2">
<code class="sql spaces"> </code><code class="sql keyword">where</code> <code class="sql plain">process_id=#{id}</code>
</div>
<div class="line number50 index49 alt1">
</div>
<div class="line number51 index50 alt2">
<code class="sql plain"></</code><code class="sql keyword">select</code><code class="sql plain">></code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
第二种是开启全局的延迟加载。通过在Mybatis的配置文件的<settings>标签下加上如下配置可开启全局的延迟加载。开启了全局的延迟加载后我们就无需再在各个嵌套的子查询上配置延迟加载了,如果有某一个嵌套的子查询是不需要延迟加载的,可以设置其fetchType=”eager”。设置在嵌套查询上的fetchType可以覆盖全局的延迟加载设置。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_167441">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain"><setting </code><code class="sql keyword">name</code><code class="sql plain">=</code><code class="sql string">"lazyLoadingEnabled"</code> <code class="sql plain">value=</code><code class="sql string">"true"</code><code class="sql plain">/></code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
<strong>1.2 分析</strong></p>
<p>
Mybatis的查询结果是由ResultSetHandler接口的handleResultSets()方法处理的。ResultSetHandler接口只有一个实现,DefaultResultSetHandler。有兴趣的朋友可以去看一下它的源码,看一下它是如何处理结果集的。对于本文的主题,延迟加载相关的一个核心的方法就是如下这个创建返回结果对象的方法。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_806711">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
<div class="line number16 index15 alt1">
16</div>
<div class="line number17 index16 alt2">
17</div>
<div class="line number18 index17 alt1">
18</div>
<div class="line number19 index18 alt2">
19</div>
<div class="line number20 index19 alt1">
20</div>
<div class="line number21 index20 alt2">
21</div>
<div class="line number22 index21 alt1">
22</div>
<div class="line number23 index22 alt2">
23</div>
<div class="line number24 index23 alt1">
24</div>
<div class="line number25 index24 alt2">
25</div>
<div class="line number26 index25 alt1">
26</div>
<div class="line number27 index26 alt2">
27</div>
<div class="line number28 index27 alt1">
28</div>
<div class="line number29 index28 alt2">
29</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain">private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {</code>
</div>
<div class="line number2 index1 alt1">
</div>
<div class="line number3 index2 alt2">
<code class="sql spaces"> </code><code class="sql plain">final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();</code>
</div>
<div class="line number4 index3 alt1">
</div>
<div class="line number5 index4 alt2">
<code class="sql spaces"> </code><code class="sql plain">final List<Object> constructorArgs = new ArrayList<Object>();</code>
</div>
<div class="line number6 index5 alt1">
</div>
<div class="line number7 index6 alt2">
<code class="sql spaces"> </code><code class="sql plain">final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);</code>
</div>
<div class="line number8 index7 alt1">
</div>
<div class="line number9 index8 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (resultObject != </code><code class="sql color1">null</code> <code class="sql plain">&& !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {</code>
</div>
<div class="line number10 index9 alt1">
</div>
<div class="line number11 index10 alt2">
<code class="sql spaces"> </code><code class="sql plain">final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();</code>
</div>
<div class="line number12 index11 alt1">
</div>
<div class="line number13 index12 alt2">
<code class="sql spaces"> </code><code class="sql keyword">for</code> <code class="sql plain">(ResultMapping propertyMapping : propertyMappings) {</code>
</div>
<div class="line number14 index13 alt1">
</div>
<div class="line number15 index14 alt2">
<code class="sql spaces"> </code><code class="sql plain">// issue gcode #109 && issue #149</code>
</div>
<div class="line number16 index15 alt1">
</div>
<div class="line number17 index16 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (propertyMapping.getNestedQueryId() != </code><code class="sql color1">null</code> <code class="sql plain">&& propertyMapping.isLazy()) {</code>
</div>
<div class="line number18 index17 alt1">
</div>
<div class="line number19 index18 alt2">
<code class="sql spaces"> </code><code class="sql keyword">return</code> <code class="sql plain">configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);</code>
</div>
<div class="line number20 index19 alt1">
</div>
<div class="line number21 index20 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number22 index21 alt1">
</div>
<div class="line number23 index22 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number24 index23 alt1">
</div>
<div class="line number25 index24 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number26 index25 alt1">
</div>
<div class="line number27 index26 alt2">
<code class="sql spaces"> </code><code class="sql keyword">return</code> <code class="sql plain">resultObject;</code>
</div>
<div class="line number28 index27 alt1">
</div>
<div class="line number29 index28 alt2">
<code class="sql plain">}</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
在上面方法中我们可以看到Mybatis先是根据正常情况创建一个返回类型对应的对象。当我们的ResultMap是包含子查询的时候,其会在我们正常返回类型对象的基础上创建对应的代理对象。对,你没有看错,就是我们的直接结果是代理对象,而不是子查询对应的属性是代理对象。默认是基于JavassistProxyFactory类创建的代理对象。可以通过Mybatis的全局配置proxyFactory来更改,可选值是CGLIB和JAVASSIST,默认是后者。需要使用CGLIB代理时注意加入CGLIB的包。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_215912">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain"><setting </code><code class="sql keyword">name</code><code class="sql plain">=</code><code class="sql string">"proxyFactory"</code> <code class="sql plain">value=</code><code class="sql string">"CGLIB"</code><code class="sql plain">/></code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
回过头来看我们之前的那个延迟加载的配置,我们的一个查询返回的是SysWfProcess类型的对象,其有一个SysWfNode集合类型的nodes属性,nodes属性是通过一个子查询查出来的,而且是延迟加载。这个时候我们来进行以下测试。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_69420">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain">@Test</code>
</div>
<div class="line number2 index1 alt1">
</div>
<div class="line number3 index2 alt2">
<code class="sql spaces"> </code><code class="sql keyword">public</code> <code class="sql plain">void testLazyLoad1() {</code>
</div>
<div class="line number4 index3 alt1">
</div>
<div class="line number5 index4 alt2">
<code class="sql spaces"> </code><code class="sql plain">SysWfProcessMapper mapper = this.session.getMapper(SysWfProcessMapper.class);</code>
</div>
<div class="line number6 index5 alt1">
</div>
<div class="line number7 index6 alt2">
<code class="sql spaces"> </code><code class="sql plain">SysWfProcess process = mapper.selectByPrimaryKey(1);</code>
</div>
<div class="line number8 index7 alt1">
</div>
<div class="line number9 index8 alt2">
<code class="sql spaces"> </code><code class="sql plain">System.</code><code class="sql keyword">out</code><code class="sql plain">.println(process.getClass());</code>
</div>
<div class="line number10 index9 alt1">
</div>
<div class="line number11 index10 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
这个时候你会发现,上面的测试代码的输出结果是一个代理类,而不是我们自己的com.elim.learn.mybatis.model.SysWfProcess类型。另外如果你启用了日志输出,并且是打印的DEBUG日志,你会看到Mybatis是发了两条SQL进行查询的。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_901991">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain">2016-12-23 15:43:21,131 DEBUG (BaseJdbcLogger.java:145) - ==> Preparing: </code><code class="sql keyword">select</code> <code class="sql plain">id, template_id, creator, create_time </code><code class="sql keyword">from</code> <code class="sql plain">sys_wf_process </code><code class="sql keyword">where</code> <code class="sql plain">id = ?</code>
</div>
<div class="line number2 index1 alt1">
</div>
<div class="line number3 index2 alt2">
<code class="sql plain">2016-12-23 15:43:21,156 DEBUG (BaseJdbcLogger.java:145) - ==> Parameters: 1(</code><code class="sql keyword">Integer</code><code class="sql plain">)</code>
</div>
<div class="line number4 index3 alt1">
</div>
<div class="line number5 index4 alt2">
<code class="sql plain">2016-12-23 15:43:21,269 DEBUG (BaseJdbcLogger.java:145) - <== Total: 1</code>
</div>
<div class="line number6 index5 alt1">
</div>
<div class="line number7 index6 alt2">
<code class="sql plain">class com.elim.learn.mybatis.model.SysWfProcess_$$_jvstc25_0</code>
</div>
<div class="line number8 index7 alt1">
</div>
<div class="line number9 index8 alt2">
<code class="sql plain">2016-12-23 15:43:21,271 DEBUG (BaseJdbcLogger.java:145) - ==> Preparing: </code><code class="sql keyword">select</code> <code class="sql plain">id, process_id, node_code, node_name </code><code class="sql keyword">from</code> <code class="sql plain">sys_wf_node </code><code class="sql keyword">where</code> <code class="sql plain">process_id=?</code>
</div>
<div class="line number10 index9 alt1">
</div>
<div class="line number11 index10 alt2">
<code class="sql plain">2016-12-23 15:43:21,272 DEBUG (BaseJdbcLogger.java:145) - ==> Parameters: 1(</code><code class="sql keyword">Integer</code><code class="sql plain">)</code>
</div>
<div class="line number12 index11 alt1">
</div>
<div class="line number13 index12 alt2">
<code class="sql plain">2016-12-23 15:43:21,274 DEBUG (BaseJdbcLogger.java:145) - <== Total: 2</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
但是如果我们把最后一个System.out.println()去掉,也就是说我们只是从数据库中查询出SysWfProcess对象,而不使用它的时候,通过查看日志输出你会发现Mybatis又只会发送一条SQL,即只是查询出SysWfProcess的信息。这是为什么呢?</p>
<p>
1.3 aggressiveLazyLoading</p>
<p>
这是因为当我们启用了延迟加载时,我们的查询结果返回的是一个代理对象,当我们访问该代理对象的方法时,都会触发加载所有的延迟加载的对象信息。这也就可以很好的解释上面的场景。但是如果是这样的设计,貌似Mybatis的延迟加载作用不大。但事实并非如此,这只是Mybatis的一个默认策略,我们可以通过Mybatis的全局配置aggressiveLazyLoading来改变它,默认是true,表示延迟加载时将在第一次访问代理对象的方法时就将全部的延迟加载对象加载出来。当设置为false时则会在我们第一次访问延迟加载的对象的时候才会从数据库加载对应的数据。注意在延迟对象未从数据库加载出来前,我们对应延迟对象的属性将是null,因为你没有对它赋值。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_283432">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain"><setting </code><code class="sql keyword">name</code><code class="sql plain">=</code><code class="sql string">"aggressiveLazyLoading"</code> <code class="sql plain">value=</code><code class="sql string">"fasle"</code><code class="sql plain">/></code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
1.4 lazyLoadTriggerMethods</p>
<p>
那如果我们设置了aggressiveLazyLoading=”false”,但又希望在调用某些方法之前把所有的延迟对象都从数据库加载出来,怎么办呢?这个时候我们可以通过lazyLoadTriggerMethods参数来指定需要加载延迟对象的方法调用。默认是equals、clone、hashCode和toString,也就是说我们在调用代理对象的这些方法之前就会把延迟加载对象从数据库加载出来。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_931771">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain"><setting </code><code class="sql keyword">name</code><code class="sql plain">=</code><code class="sql string">"lazyLoadTriggerMethods"</code> <code class="sql plain">value=</code><code class="sql string">"equals,clone,hashCode,toString"</code> <code class="sql plain">/></code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
Mybatis延迟加载生成的代理对象的代理过程,可以参考ProxyFactory的创建代理对象的过程,以下是基于Javassist创建的代理对象的代理过程,基于CGLIB的代理也是类似的。从下面的代码我们可以看到Mybatis的代理对象需要从数据库加载延迟对象时是在目标方法被调用以前发生的,这就可以保证我们的目标方法被调用时延迟加载的对象已经从数据库中加载出来了。</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightersql" id="highlighter_372656">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
<div class="line number16 index15 alt1">
16</div>
<div class="line number17 index16 alt2">
17</div>
<div class="line number18 index17 alt1">
18</div>
<div class="line number19 index18 alt2">
19</div>
<div class="line number20 index19 alt1">
20</div>
<div class="line number21 index20 alt2">
21</div>
<div class="line number22 index21 alt1">
22</div>
<div class="line number23 index22 alt2">
23</div>
<div class="line number24 index23 alt1">
24</div>
<div class="line number25 index24 alt2">
25</div>
<div class="line number26 index25 alt1">
26</div>
<div class="line number27 index26 alt2">
27</div>
<div class="line number28 index27 alt1">
28</div>
<div class="line number29 index28 alt2">
29</div>
<div class="line number30 index29 alt1">
30</div>
<div class="line number31 index30 alt2">
31</div>
<div class="line number32 index31 alt1">
32</div>
<div class="line number33 index32 alt2">
33</div>
<div class="line number34 index33 alt1">
34</div>
<div class="line number35 index34 alt2">
35</div>
<div class="line number36 index35 alt1">
36</div>
<div class="line number37 index36 alt2">
37</div>
<div class="line number38 index37 alt1">
38</div>
<div class="line number39 index38 alt2">
39</div>
<div class="line number40 index39 alt1">
40</div>
<div class="line number41 index40 alt2">
41</div>
<div class="line number42 index41 alt1">
42</div>
<div class="line number43 index42 alt2">
43</div>
<div class="line number44 index43 alt1">
44</div>
<div class="line number45 index44 alt2">
45</div>
<div class="line number46 index45 alt1">
46</div>
<div class="line number47 index46 alt2">
47</div>
<div class="line number48 index47 alt1">
48</div>
<div class="line number49 index48 alt2">
49</div>
<div class="line number50 index49 alt1">
50</div>
<div class="line number51 index50 alt2">
51</div>
<div class="line number52 index51 alt1">
52</div>
<div class="line number53 index52 alt2">
53</div>
<div class="line number54 index53 alt1">
54</div>
<div class="line number55 index54 alt2">
55</div>
<div class="line number56 index55 alt1">
56</div>
<div class="line number57 index56 alt2">
57</div>
<div class="line number58 index57 alt1">
58</div>
<div class="line number59 index58 alt2">
59</div>
<div class="line number60 index59 alt1">
60</div>
<div class="line number61 index60 alt2">
61</div>
<div class="line number62 index61 alt1">
62</div>
<div class="line number63 index62 alt2">
63</div>
<div class="line number64 index63 alt1">
64</div>
<div class="line number65 index64 alt2">
65</div>
<div class="line number66 index65 alt1">
66</div>
<div class="line number67 index66 alt2">
67</div>
<div class="line number68 index67 alt1">
68</div>
<div class="line number69 index68 alt2">
69</div>
<div class="line number70 index69 alt1">
70</div>
<div class="line number71 index70 alt2">
71</div>
<div class="line number72 index71 alt1">
72</div>
<div class="line number73 index72 alt2">
73</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="sql plain">@Override</code>
</div>
<div class="line number2 index1 alt1">
</div>
<div class="line number3 index2 alt2">
<code class="sql spaces"> </code><code class="sql keyword">public</code> <code class="sql plain">Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {</code>
</div>
<div class="line number4 index3 alt1">
</div>
<div class="line number5 index4 alt2">
<code class="sql spaces"> </code><code class="sql plain">final String methodName = method.getName();</code>
</div>
<div class="line number6 index5 alt1">
</div>
<div class="line number7 index6 alt2">
<code class="sql spaces"> </code><code class="sql plain">try {</code>
</div>
<div class="line number8 index7 alt1">
</div>
<div class="line number9 index8 alt2">
<code class="sql spaces"> </code><code class="sql plain">synchronized (lazyLoader) {</code>
</div>
<div class="line number10 index9 alt1">
</div>
<div class="line number11 index10 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (WRITE_REPLACE_METHOD.equals(methodName)) {</code>
</div>
<div class="line number12 index11 alt1">
</div>
<div class="line number13 index12 alt2">
<code class="sql spaces"> </code><code class="sql plain">Object original = </code><code class="sql color1">null</code><code class="sql plain">;</code>
</div>
<div class="line number14 index13 alt1">
</div>
<div class="line number15 index14 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (constructorArgTypes.isEmpty()) {</code>
</div>
<div class="line number16 index15 alt1">
</div>
<div class="line number17 index16 alt2">
<code class="sql spaces"> </code><code class="sql plain">original = objectFactory.</code><code class="sql keyword">create</code><code class="sql plain">(type);</code>
</div>
<div class="line number18 index17 alt1">
</div>
<div class="line number19 index18 alt2">
<code class="sql spaces"> </code><code class="sql plain">} </code><code class="sql keyword">else</code> <code class="sql plain">{</code>
</div>
<div class="line number20 index19 alt1">
</div>
<div class="line number21 index20 alt2">
<code class="sql spaces"> </code><code class="sql plain">original = objectFactory.</code><code class="sql keyword">create</code><code class="sql plain">(type, constructorArgTypes, constructorArgs);</code>
</div>
<div class="line number22 index21 alt1">
</div>
<div class="line number23 index22 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number24 index23 alt1">
</div>
<div class="line number25 index24 alt2">
<code class="sql spaces"> </code><code class="sql plain">PropertyCopier.copyBeanProperties(type, enhanced, original);</code>
</div>
<div class="line number26 index25 alt1">
</div>
<div class="line number27 index26 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (lazyLoader.</code><code class="sql keyword">size</code><code class="sql plain">() > 0) {</code>
</div>
<div class="line number28 index27 alt1">
</div>
<div class="line number29 index28 alt2">
<code class="sql spaces"> </code><code class="sql keyword">return</code> <code class="sql plain">new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);</code>
</div>
<div class="line number30 index29 alt1">
</div>
<div class="line number31 index30 alt2">
<code class="sql spaces"> </code><code class="sql plain">} </code><code class="sql keyword">else</code> <code class="sql plain">{</code>
</div>
<div class="line number32 index31 alt1">
</div>
<div class="line number33 index32 alt2">
<code class="sql spaces"> </code><code class="sql keyword">return</code> <code class="sql plain">original;</code>
</div>
<div class="line number34 index33 alt1">
</div>
<div class="line number35 index34 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number36 index35 alt1">
</div>
<div class="line number37 index36 alt2">
<code class="sql spaces"> </code><code class="sql plain">} </code><code class="sql keyword">else</code> <code class="sql plain">{</code>
</div>
<div class="line number38 index37 alt1">
</div>
<div class="line number39 index38 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (lazyLoader.</code><code class="sql keyword">size</code><code class="sql plain">() > 0 && !FINALIZE_METHOD.equals(methodName)) {</code>
</div>
<div class="line number40 index39 alt1">
</div>
<div class="line number41 index40 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (aggressive || lazyLoadTriggerMethods.</code><code class="sql keyword">contains</code><code class="sql plain">(methodName)) {</code>
</div>
<div class="line number42 index41 alt1">
</div>
<div class="line number43 index42 alt2">
<code class="sql spaces"> </code><code class="sql plain">lazyLoader.loadAll();</code>
</div>
<div class="line number44 index43 alt1">
</div>
<div class="line number45 index44 alt2">
<code class="sql spaces"> </code><code class="sql plain">} </code><code class="sql keyword">else</code> <code class="sql plain">if (PropertyNamer.isProperty(methodName)) {</code>
</div>
<div class="line number46 index45 alt1">
</div>
<div class="line number47 index46 alt2">
<code class="sql spaces"> </code><code class="sql plain">final String property = PropertyNamer.methodToProperty(methodName);</code>
</div>
<div class="line number48 index47 alt1">
</div>
<div class="line number49 index48 alt2">
<code class="sql spaces"> </code><code class="sql plain">if (lazyLoader.hasLoader(property)) {</code>
</div>
<div class="line number50 index49 alt1">
</div>
<div class="line number51 index50 alt2">
<code class="sql spaces"> </code><code class="sql plain">lazyLoader.</code><code class="sql keyword">load</code><code class="sql plain">(property);</code>
</div>
<div class="line number52 index51 alt1">
</div>
<div class="line number53 index52 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number54 index53 alt1">
</div>
<div class="line number55 index54 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number56 index55 alt1">
</div>
<div class="line number57 index56 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number58 index57 alt1">
</div>
<div class="line number59 index58 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number60 index59 alt1">
</div>
<div class="line number61 index60 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number62 index61 alt1">
</div>
<div class="line number63 index62 alt2">
<code class="sql spaces"> </code><code class="sql keyword">return</code> <code class="sql plain">methodProxy.invoke(enhanced, args);</code>
</div>
<div class="line number64 index63 alt1">
</div>
<div class="line number65 index64 alt2">
<code class="sql spaces"> </code><code class="sql plain">} catch (Throwable t) {</code>
</div>
<div class="line number66 index65 alt1">
</div>
<div class="line number67 index66 alt2">
<code class="sql spaces"> </code><code class="sql plain">throw ExceptionUtil.unwrapThrowable(t);</code>
</div>
<div class="line number68 index67 alt1">
</div>
<div class="line number69 index68 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number70 index69 alt1">
</div>
<div class="line number71 index70 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
<div class="line number72 index71 alt1">
</div>
<div class="line number73 index72 alt2">
<code class="sql spaces"> </code><code class="sql plain">}</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
本文是介绍的都是基于<collection>这种关联,其实<association>关联的对象的延迟加载也是一样的,它们的默认策略也是一样的。</p>
<p>
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!</p>
<p>
原文链接:https://my.oschina.net/elim1/blog/817302</p>
頁:
[1]