想了解返回值,我们需要了解resultType
,resultMap
以及接口方法中定义的返回值。
我们先看resultType
和resultMap
大家应该都知道在MyBatis的<select>
标签中有两种设置返回值的方式,分别是resultMap
和resultType
。
处理resultMap
和resultType
的代码如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setStatementResultMap</span>( String resultMap, Class<?> resultType, ResultSetType resultSetType, MappedStatement.Builder statementBuilder) { resultMap = applyCurrentNamespace(resultMap, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>); List<ResultMap> resultMaps = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<ResultMap>(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (resultMap != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { String[] resultMapNames = resultMap.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">","</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (String resultMapName : resultMapNames) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { resultMaps.add(configuration.getResultMap(resultMapName.trim())); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IllegalArgumentException e) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IncompleteElementException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Could not find result map "</span> + resultMapName, e); } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (resultType != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { ResultMap.Builder inlineResultMapBuilder = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ResultMap.Builder( configuration, statementBuilder.id() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-Inline"</span>, resultType, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<ResultMapping>(), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); resultMaps.add(inlineResultMapBuilder.build()); } statementBuilder.resultMaps(resultMaps); statementBuilder.resultSetType(resultSetType); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>
可以看到这里会优先处理resultMap
,但是也使用了resultType
。
接下来看MyBatis获取数据后,如果处理一行结果(以简单数据为例,不考虑嵌套情况):
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Object <span class="hljs-title" style="box-sizing: border-box;">getRowValue</span>(ResultSetWrapper rsw, ResultMap resultMap) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> SQLException { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> ResultLoaderMap lazyLoader = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ResultLoaderMap(); Object resultObject = createResultObject(rsw, resultMap, lazyLoader, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (resultObject != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> MetaObject metaObject = configuration.newMetaObject(resultObject); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> foundValues = resultMap.getConstructorResultMappings().size() > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) || foundValues; foundValues = lazyLoader.size() > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> || foundValues; resultObject = foundValues ? resultObject : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> resultObject; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> resultObject; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
上面这段代码中重要的代码如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) || foundValues;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
if中判断的是当前是否支持自动映射(可以配置),这一点很重要,如果不支持,那么没法使用resultType
方式,必须用resultMap
方式,如果支持,resultType
方式和resultMap
方式可以同时使用。
这里的基本逻辑是先对没有resultMap
的属性自动映射赋值,通过applyAutomaticMappings
实现。
如果对象有resultMap
,那么还会进行applyPropertyMappings
方法。
也就是先处理resultType
中自动映射的字段,在处理resultMap
中的配置的字段,两者可以同时使用!
下面按照顺序分别说两种方式。
resultType
方式如果支持自动映射,那么会执行applyAutomaticMappings
,这里面有metaObject
参数。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> MetaObject metaObject = configuration.newMetaObject(resultObject);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
我们看看创建metaObject
最关键的一个地方,在Reflector
类中:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (String propName : readablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
这里将实体中的属性名,做了一个映射,是大写的对应实际的属性名。例如ID:id
。
在applyAutomaticMappings
中的第一行,首先获取没有映射的列名:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
获取列名的时候:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (String columnName : columnNames) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String upperColumnName = columnName.toUpperCase(Locale.ENGLISH); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mappedColumns.contains(upperColumnName)) { mappedColumnNames.add(upperColumnName); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { unmappedColumnNames.add(columnName); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
注意这里将列名转换为大写形式,同时保存了mappedColumnNames
映射的列和unmappedColumnNames
未映射的列。
因为不管是属性名还是查询列都是大写的,所以只要列名和属性名大写一致,就会匹配上。
因此我们在写sql的时候,不需要对查询列的大小写进行转换,自动匹配是不区分大小写的。
resultMap
方式这种方式也很简单,上面提到了mappedColumnNames
,在判断是否为映射列的时候,使用mappedColumns.contains(upperColumnName)
进行判断,mappedColumns
是我们配置的映射的列,那是不是我们配置的时候必须大写呢?
实际上不用,这里也不区分大小写,在<result column="xxx" ../>
的column
也不区分大小写,看下面的代码:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (ResultMapping compositeResultMapping : resultMapping.getComposites()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String compositeColumn = compositeResultMapping.getColumn(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (compositeColumn != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH)); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
这里也转换为了大写。
到这里关于resultTypt
和resultMap
就结束了,但是有一个简单的问题,很多人不懂,是什么?看下个标题。
接口返回值通常是一个结果,或者是List
和数组。
在MapperMethod
中的部分代码如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (method.returnsMany()) { result = executeForMany(sqlSession, args); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (method.returnsMap()) { result = executeForMap(sqlSession, args); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
可以看到查询结果有4中情况,void
,list
(和array
),map
,one
。
这里重要就是if的判断条件,这种判断条件计算方法:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnType = method.getReturnType(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnsVoid = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>.class.equals(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnType); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnsMany = (configuration.getObjectFactory().isCollection(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnType) || <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.returnType.isArray());</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
可以看到,这些条件完全就是通过方法的返回值决定的。所以如果你写的返回值是数组或者集合,返回的结果就是多个。
如果返回值本身有多个,但是返回值写了一个POJO,不是集合或者数组时会怎样?
答案是会报错TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size())
。
不管是返回一个结果还是多个结果,MyBatis都是安装多个结果进行查询,selectOne
是查询一个,selectList
是查询多个,我们看看selectOne
代码:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <T> T <span class="hljs-title" style="box-sizing: border-box;">selectOne</span>(String statement, Object parameter) { List<T> list = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.<T>selectList(statement, parameter); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (list.size() == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> list.get(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (list.size() > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TooManyResultsException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Expected one result (or null) to be returned by selectOne(), but found: "</span> + list.size()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
注意看:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">List<T> list = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.<T>selectList(statement, parameter);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
实际上,不管查询一个还是多个结果,MyBatis都是先按多个结果进行查询。拿到list
结果后在判断。
如果是查询一个结果的情况,那么list
最多只能有一个返回值。通过上面代码的if else if esle
可以很明白的理解。
resultTyp
,resultMap
和返回值多少有关系吗?没有任何关系。
通过前面resultType
和resultMap
的内容,我们应该知道,这个属性是配置JDBC查询结果如何映射到一个对象上的。
不管返回值是什么或者是几个,都是按照resultType
和resultMap
生成返回结果。
返回结果的类型由resultType
和resultMap
决定。
返回结果的类型由resultType
和resultMap
决定,是不是很诧异???
实际上就是这种情况。。
举个例子,有个实体Country
和Country2
。
接口中List<Country> selectAll()
,xml中的<select id="selectAll" resultType="Country2">
.
当你通过接口调用的时候,返回值是什么?你以为自己的List
中的对象类型是Country
,但他们实际上都是Country2
如果接口方法为Country selectById(Integer id)
,xml中为<select id="selectById" resultType="Country2">
,由于类型不一致,查询的时候才会报错:java.lang.ClassCastException: xx.Country2 cannot be cast to xx.Country
这是因为接口调用方式是对命名空间方式调用的封装。
当你通过命名空间方式调用的时候,返回结果的类型是什么?
就是由resultType
和resultMap
决定的类型,这很容易理解。但是换成接口就觉得不一样了。
这是由于接口方法方式多了返回值,所以我们会认为返回的一定是这个类型。实际上是错的。
当使用纯注解方式时,接口的返回值类型可以起到作用,如果没有使用@ResultType
注解指定返回值类型,那么就会使用这里写的返回值类型作为resultType
。