PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/src/site/zh/xdoc/sqlmap-xml.xml

https://github.com/dayifu/mybatis-3
XML | 1898 lines | 1649 code | 232 blank | 17 comment | 0 complexity | 667c9cb7abc7c8f7ed9438fac25e9d36 MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3. Copyright 2010-2012 the original author or authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. -->
  14. <!-- version: $Id$ -->
  15. <document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  16. xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
  17. <properties>
  18. <title>MyBatis 3 | Mapper XML 文件</title>
  19. <author email="clinton.begin@gmail.com">Clinton Begin</author>
  20. <author email="nanlei1987@gmail.com">Nan Lei</author>
  21. <author email="echowdx@gmail.com">Dongxu Wang</author>
  22. </properties>
  23. <body>
  24. <section name="Mapper XML 文件">
  25. <p>MyBatis 的真正强大在于它的映射语句也是它的魔力所在由于它的异常强大映射器的 XML 文件就显得相对简单如果拿它跟具有相同功能的 JDBC 代码进行对比你会立即发现省掉了将近 95% 的代码MyBatis 就是针对 SQL 构建的并且比普通的方法做的更好</p>
  26. <p>SQL 映射文件有很少的几个顶级元素按照它们应该被定义的顺序</p>
  27. <ul>
  28. <li>
  29. <code>cache</code>
  30. 给定命名空间的缓存配置
  31. </li>
  32. <li>
  33. <code>cache-ref</code>
  34. 其他命名空间缓存配置的引用
  35. </li>
  36. <li>
  37. <code>resultMap</code>
  38. 是最复杂也是最强大的元素用来描述如何从数据库结果集中来加载对象
  39. </li>
  40. <li>
  41. <strike>
  42. <code>parameterMap</code>
  43. 已废弃老式风格的参数映射内联参数是首选,这个元素可能在将来被移除这里不会记录
  44. </strike>
  45. </li>
  46. <li>
  47. <code>sql</code>
  48. 可被其他语句引用的可重用语句块
  49. </li>
  50. <li>
  51. <code>insert</code>
  52. 映射插入语句
  53. </li>
  54. <li>
  55. <code>update</code>
  56. 映射更新语句
  57. </li>
  58. <li>
  59. <code>delete</code>
  60. 映射删除语句
  61. </li>
  62. <li>
  63. <code>select</code>
  64. 映射查询语句
  65. </li>
  66. </ul>
  67. <p>下一部分将从语句本身开始来描述每个元素的细节</p>
  68. <subsection name="select">
  69. <p>查询语句是 MyBatis 中最常用的元素之一光能把数据存到数据库中价值并不大如果还能重新取出来才有用多数应用也都是查询比修改要频繁对每个插入更新或删除操作通常对应多个查询操作这是 MyBatis 的基本原则之一也是将焦点和努力放到查询和结果映射的原因简单查询的 select 元素是非常简单的比如
  70. </p>
  71. <source><![CDATA[<select id="selectPerson" parameterType="int" resultType="hashmap">
  72. SELECT * FROM PERSON WHERE ID = #{id}
  73. </select>]]></source>
  74. <p>这个语句被称作 selectPerson接受一个 int Integer类型的参数并返回一个 HashMap 类型的对象其中的键是列名值便是结果行中的对应值
  75. </p>
  76. <p>注意参数符号</p>
  77. <source><![CDATA[#{id}]]></source>
  78. <p>这就告诉 MyBatis 创建一个预处理语句参数通过 JDBC这样的一个参数在 SQL 中会由一个?来标识并被传递到一个新的预处理语句中就像这样
  79. </p>
  80. <source><![CDATA[// Similar JDBC code, NOT MyBatis…
  81. String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
  82. PreparedStatement ps = conn.prepareStatement(selectPerson);
  83. ps.setInt(1,id);]]></source>
  84. <p>当然这需要很多单独的 JDBC 的代码来提取结果并将它们映射到对象实例中这就是 MyBatis 节省你时间的地方我们需要深入了解参数和结果映射细节部分我们下面来了解
  85. </p>
  86. <p>select 元素有很多属性允许你配置来决定每条语句的作用细节
  87. </p>
  88. <source><![CDATA[<select
  89. id="selectPerson"
  90. parameterType="int"
  91. parameterMap="deprecated"
  92. resultType="hashmap"
  93. resultMap="personResultMap"
  94. flushCache="false"
  95. useCache="true"
  96. timeout="10000"
  97. fetchSize="256"
  98. statementType="PREPARED"
  99. resultSetType="FORWARD_ONLY">]]></source>
  100. <table>
  101. <caption>Select Attributes</caption>
  102. <thead>
  103. <tr>
  104. <th>属性</th>
  105. <th>描述</th>
  106. </tr>
  107. </thead>
  108. <tbody>
  109. <tr>
  110. <td><code>id</code></td>
  111. <td>
  112. 在命名空间中唯一的标识符可以被用来引用这条语句
  113. </td>
  114. </tr>
  115. <tr>
  116. <td><code>parameterType</code></td>
  117. <td>
  118. 将会传入这条语句的参数类的完全限定名或别名这个属性是可选的因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数默认值为 unset
  119. </td>
  120. </tr>
  121. <tr>
  122. <td>
  123. <strike>parameterMap</strike>
  124. </td>
  125. <td>
  126. <strike>这是引用外部 parameterMap 的已经被废弃的方法使用内联参数映射和 parameterType 属性
  127. </strike>
  128. </td>
  129. </tr>
  130. <tr>
  131. <td><code>resultType</code></td>
  132. <td>从这条语句中返回的期望类型的类的完全限定名或别名注意如果是集合情形那应该是集合可以包含的类型而不能是集合本身使用 resultType resultMap但不能同时使用
  133. </td>
  134. </tr>
  135. <tr>
  136. <td><code>resultMap</code></td>
  137. <td>外部 resultMap 的命名引用结果集的映射是 MyBatis 最强大的特性对其有一个很好的理解的话许多复杂映射的情形都能迎刃而解使用 resultMap resultType但不能同时使用
  138. </td>
  139. </tr>
  140. <tr>
  141. <td><code>flushCache</code></td>
  142. <td>将其设置为 true任何时候只要语句被调用都会导致本地缓存和二级缓存都会被清空默认值false
  143. </td>
  144. </tr>
  145. <tr>
  146. <td><code>useCache</code></td>
  147. <td>将其设置为 true将会导致本条语句的结果被二级缓存默认值 select 元素为 true
  148. </td>
  149. </tr>
  150. <tr>
  151. <td><code>timeout</code></td>
  152. <td>这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数默认值为 unset依赖驱动
  153. </td>
  154. </tr>
  155. <tr>
  156. <td><code>fetchSize</code></td>
  157. <td>这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等默认值为 unset依赖驱动
  158. </td>
  159. </tr>
  160. <tr>
  161. <td><code>statementType</code></td>
  162. <td>STATEMENTPREPARED CALLABLE 的一个这会让 MyBatis 分别使用 StatementPreparedStatement CallableStatement默认值PREPARED
  163. </td>
  164. </tr>
  165. <tr>
  166. <td><code>resultSetType</code></td>
  167. <td>FORWARD_ONLYSCROLL_SENSITIVE SCROLL_INSENSITIVE 中的一个默认值为 unset 依赖驱动
  168. </td>
  169. </tr>
  170. <tr>
  171. <td><code>databaseId</code></td>
  172. <td>如果配置了 databaseIdProviderMyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句如果带或者不带的语句都有则不带的会被忽略
  173. </td>
  174. </tr>
  175. <tr>
  176. <td><code>resultOrdered</code></td>
  177. <td>这个设置仅针对嵌套结果 select 语句适用如果为 true就是假设包含了嵌套结果集或是分组了这样的话当返回一个主结果行的时候就不会发生有对前面结果集的引用的情况这就使得在获取嵌套的结果集的时候不至于导致内存不够用默认值<code>false</code>
  178. </td>
  179. </tr>
  180. <tr>
  181. <td><code>resultSets</code></td>
  182. <td>这个设置仅对多结果集的情况适用它将列出语句执行后返回的结果集并每个结果集给一个名称名称是逗号分隔的
  183. </td>
  184. </tr>
  185. </tbody>
  186. </table>
  187. </subsection>
  188. <subsection name="insert, update 和 delete">
  189. <p>
  190. 数据变更语句 insertupdate delete 的实现非常接近
  191. </p>
  192. <source><![CDATA[<insert
  193. id="insertAuthor"
  194. parameterType="domain.blog.Author"
  195. flushCache="true"
  196. statementType="PREPARED"
  197. keyProperty=""
  198. keyColumn=""
  199. useGeneratedKeys=""
  200. timeout="20">
  201. <update
  202. id="insertAuthor"
  203. parameterType="domain.blog.Author"
  204. flushCache="true"
  205. statementType="PREPARED"
  206. timeout="20">
  207. <delete
  208. id="insertAuthor"
  209. parameterType="domain.blog.Author"
  210. flushCache="true"
  211. statementType="PREPARED"
  212. timeout="20">]]></source>
  213. <table>
  214. <caption>Insert, Update Delete 的属性</caption>
  215. <thead>
  216. <tr>
  217. <th>属性</th>
  218. <th>描述</th>
  219. </tr>
  220. </thead>
  221. <tbody>
  222. <tr>
  223. <td><code>id</code></td>
  224. <td>命名空间中的唯一标识符可被用来代表这条语句</td>
  225. </tr>
  226. <tr>
  227. <td><code>parameterType</code></td>
  228. <td>将要传入语句的参数的完全限定类名或别名这个属性是可选的因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数默认值为 unset
  229. </td>
  230. </tr>
  231. <tr>
  232. <td>
  233. <strike><code>parameterMap</code></strike>
  234. </td>
  235. <td>
  236. <strike>这是引用外部 parameterMap 的已经被废弃的方法使用内联参数映射和 parameterType 属性
  237. </strike>
  238. </td>
  239. </tr>
  240. <tr>
  241. <td><code>flushCache</code></td>
  242. <td>将其设置为 true任何时候只要语句被调用都会导致本地缓存和二级缓存都会被清空默认值true对应插入更新和删除语句
  243. </td>
  244. </tr>
  245. <tr>
  246. <td><code>timeout</code></td>
  247. <td>这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数默认值为 unset依赖驱动
  248. </td>
  249. </tr>
  250. <tr>
  251. <td><code>statementType</code></td>
  252. <td>STATEMENTPREPARED CALLABLE 的一个这会让 MyBatis 分别使用 StatementPreparedStatement CallableStatement默认值PREPARED
  253. </td>
  254. </tr>
  255. <tr>
  256. <td><code>useGeneratedKeys</code></td>
  257. <td>仅对 insert update 有用这会令 MyBatis 使用 JDBC getGeneratedKeys 方法来取出由数据库内部生成的主键比如 MySQL SQL Server 这样的关系数据库管理系统的自动递增字段默认值false
  258. </td>
  259. </tr>
  260. <tr>
  261. <td><code>keyProperty</code></td>
  262. <td>仅对 insert update 有用唯一标记一个属性MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值默认<code>unset</code>如果希望得到多个生成的列也可以是逗号分隔的属性名称列表
  263. </td>
  264. </tr>
  265. <tr>
  266. <td><code>keyColumn</code></td>
  267. <td>仅对 insert update 有用通过生成的键值设置表中的列名这个设置仅在某些数据库 PostgreSQL是必须的当主键列不是表中的第一列的时候需要设置如果希望得到多个生成的列也可以是逗号分隔的属性名称列表
  268. </td>
  269. </tr>
  270. <tr>
  271. <td><code>databaseId</code></td>
  272. <td>如果配置了 databaseIdProviderMyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句如果带或者不带的语句都有则不带的会被忽略
  273. </td>
  274. </tr>
  275. </tbody>
  276. </table>
  277. <p>下面就是 insertupdate delete 语句的示例</p>
  278. <source><![CDATA[<insert id="insertAuthor">
  279. insert into Author (id,username,password,email,bio)
  280. values (#{id},#{username},#{password},#{email},#{bio})
  281. </insert>
  282. <update id="updateAuthor">
  283. update Author set
  284. username = #{username},
  285. password = #{password},
  286. email = #{email},
  287. bio = #{bio}
  288. where id = #{id}
  289. </update>
  290. <delete id="deleteAuthor">
  291. delete from Author where id = #{id}
  292. </delete>]]></source>
  293. <p>如前所述插入语句的配置规则更加丰富在插入语句里面有一些额外的属性和子元素用来处理主键的生成而且有多种生成方式</p>
  294. <p>首先如果你的数据库支持自动生成主键的字段比如 MySQL SQL Server那么你可以设置 useGeneratedKeys=true然后再把 keyProperty 设置到目标属性上就OK了例如如果上面的 Author 表已经对 id 使用了自动生成的列类型那么语句可以修改为:</p>
  295. <source><![CDATA[<insert id="insertAuthor" useGeneratedKeys="true"
  296. keyProperty="id">
  297. insert into Author (username,password,email,bio)
  298. values (#{username},#{password},#{email},#{bio})
  299. </insert>]]></source>
  300. <p>对于不支持自动生成类型的数据库或可能不支持自动生成主键 JDBC 驱动来说MyBatis 有另外一种方法来生成主键
  301. </p>
  302. <p>这里有一个简单甚至很傻的示例它可以生成一个随机 ID你最好不要这么做但这里展示了 MyBatis 处理问题的灵活性及其所关心的广度
  303. </p>
  304. <source><![CDATA[<insert id="insertAuthor">
  305. <selectKey keyProperty="id" resultType="int" order="BEFORE">
  306. select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
  307. </selectKey>
  308. insert into Author
  309. (id, username, password, email,bio, favourite_section)
  310. values
  311. (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
  312. </insert>]]></source>
  313. <p>在上面的示例中selectKey 元素将会首先运行Author id 会被设置然后插入语句会被调用这给你了一个和数据库中来处理自动生成的主键类似的行为避免了使 Java 代码变得复杂
  314. </p>
  315. <p>selectKey 元素描述如下
  316. </p>
  317. <source><![CDATA[<selectKey
  318. keyProperty="id"
  319. resultType="int"
  320. order="BEFORE"
  321. statementType="PREPARED">]]></source>
  322. <table>
  323. <caption>selectKey 的属性</caption>
  324. <thead>
  325. <tr>
  326. <th>属性</th>
  327. <th>描述</th>
  328. </tr>
  329. </thead>
  330. <tbody>
  331. <tr>
  332. <td><code>keyProperty</code></td>
  333. <td>selectKey 语句结果应该被设置的目标属性如果希望得到多个生成的列也可以是逗号分隔的属性名称列表
  334. </td>
  335. </tr>
  336. <tr>
  337. <td><code>keyColumn</code></td>
  338. <td>匹配属性的返回结果集中的列名称如果希望得到多个生成的列也可以是逗号分隔的属性名称列表
  339. </td>
  340. </tr>
  341. <tr>
  342. <td><code>resultType</code></td>
  343. <td>结果的类型MyBatis 通常可以推算出来但是为了更加确定写上也不会有什么问题MyBatis 允许任何简单类型用作主键的类型包括字符串如果希望作用于多个生成的列则可以使用一个包含期望属性的 Object 或一个 Map
  344. </td>
  345. </tr>
  346. <tr>
  347. <td><code>order</code></td>
  348. <td>这可以被设置为 BEFORE AFTER如果设置为 BEFORE那么它会首先选择主键设置 keyProperty 然后执行插入语句如果设置为 AFTER那么先执行插入语句然后是 selectKey 元素 - 这和像 Oracle 的数据库相似在插入语句内部可能有嵌入索引调用
  349. </td>
  350. </tr>
  351. <tr>
  352. <td><code>statementType</code></td>
  353. <td>与前面相同MyBatis 支持 STATEMENTPREPARED CALLABLE 语句的映射类型分别代表 PreparedStatement CallableStatement 类型
  354. </td>
  355. </tr>
  356. </tbody>
  357. </table>
  358. </subsection>
  359. <subsection name="sql">
  360. <p>这个元素可以被用来定义可重用的 SQL 代码段可以包含在其他语句中比如
  361. </p>
  362. <source><![CDATA[<sql id="userColumns"> id,username,password </sql>]]></source>
  363. <p>这个 SQL 片段可以被包含在其他语句中例如
  364. </p>
  365. <source><![CDATA[<select id="selectUsers" resultType="map">
  366. select <include refid="userColumns"/>
  367. from some_table
  368. where id = #{id}
  369. </select>]]></source>
  370. </subsection>
  371. <subsection name="参数(Parameters)">
  372. <p>前面的所有语句中你所见到的都是简单参数的例子实际上参数是 MyBatis 非常强大的元素对于简单的做法大概 90% 的情况参数都很少比如
  373. </p>
  374. <source><![CDATA[<select id="selectUsers" resultType="User">
  375. select id, username, password
  376. from users
  377. where id = #{id}
  378. </select>]]></source>
  379. <p>上面的这个示例说明了一个非常简单的命名参数映射参数类型被设置为 <code>int</code>这样这个参数就可以被设置成任何内容原生的类型或简单数据类型比如整型和字符串因为没有相关属性它会完全用参数值来替代然而如果传入一个复杂的对象行为就会有一点不同了比如
  380. </p>
  381. <source><![CDATA[<insert id="insertUser" parameterType="User">
  382. insert into users (id, username, password)
  383. values (#{id}, #{username}, #{password})
  384. </insert>]]></source>
  385. <p>如果 User 类型的参数对象传递到了语句中idusername password 属性将会被查找然后将它们的值传入预处理语句的参数中
  386. </p>
  387. <p>这点对于向语句中传参是比较好的而且又简单不过参数映射的功能远不止于此
  388. </p>
  389. <p>首先 MyBatis 的其他部分一样参数也可以指定一个特殊的数据类型
  390. </p>
  391. <source><![CDATA[#{property,javaType=int,jdbcType=NUMERIC}]]></source>
  392. <p> MyBatis 的剩余部分一样javaType 通常可以从参数对象中来去确定前提是只要对象不是一个 HashMap那么 javaType 应该被确定来保证使用正确类型处理器
  393. </p>
  394. <p><span class="label important">NOTE</span> 如果 null 被当作值来传递对于所有可能为空的列JDBC Type 是需要的你可以自己通过阅读预处理语句的 setNull() 方法的 JavaDocs 文档来研究这种情况
  395. </p>
  396. <p>为了以后定制类型处理方式你也可以指定一个特殊的类型处理器类或别名比如
  397. </p>
  398. <source><![CDATA[#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}]]></source>
  399. <p>尽管看起来配置变得越来越繁琐但实际上是很少去设置它们
  400. </p>
  401. <p>对于数值类型还有一个小数保留位数的设置来确定小数点后保留的位数
  402. </p>
  403. <source><![CDATA[#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}]]></source>
  404. <p>最后mode 属性允许你指定 INOUT INOUT 参数如果参数为 OUT INOUT参数对象属性的真实值将会被改变就像你在获取输出参数时所期望的那样如果 mode OUT INOUT而且 jdbcType CURSOR(也就是 Oracle REFCURSOR)你必须指定一个 resultMap 来映射结果集到参数类型要注意这里的 javaType 属性是可选的如果左边的空白是 jdbcType CURSOR 类型它会自动地被设置为结果集
  405. </p>
  406. <source><![CDATA[#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}]]></source>
  407. <p>MyBatis 也支持很多高级的数据类型比如结构体但是当注册 out 参数时你必须告诉它语句类型名称比如再次提示在实际中要像这样不能换行
  408. </p>
  409. <source><![CDATA[#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}]]></source>
  410. <p>尽管所有这些强大的选项很多时候你只简单指定属性名其他的事情 MyBatis 会自己去推断最多你需要为可能为空的列名指定 <code>jdbcType</code>
  411. </p>
  412. <source><![CDATA[#{firstName}
  413. #{middleInitial,jdbcType=VARCHAR}
  414. #{lastName}]]></source>
  415. <h4>
  416. 字符串替换
  417. </h4>
  418. <p>默认情况下,使用#{}格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值比如?这样做更安全更迅速通常也是首选做法不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串比如 ORDER BY你可以这样来使用
  419. </p>
  420. <source><![CDATA[ORDER BY ${columnName}]]></source>
  421. <p>这里 MyBatis 不会修改或转义字符串
  422. </p>
  423. <p>
  424. <span class="label important">NOTE</span> 以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的会导致潜在的 SQL 注入攻击因此要么不允许用户输入这些字段要么自行转义并检验
  425. </p>
  426. </subsection>
  427. <subsection name="Result Maps">
  428. <p>
  429. resultMap 元素是 MyBatis 中最重要最强大的元素它就是让你远离 90%的需要从结果
  430. 集中取出数据的 JDBC 代码的那个东西,
  431. 而且在一些情形下允许你做一些 JDBC 不支持的事
  432. 事实上,
  433. 编写相似于对复杂语句联合映射这些等同的代码,
  434. 也许可以跨过上千行的代码
  435. ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们
  436. 的关系
  437. </p>
  438. <p>
  439. 你已经看到简单映射语句的示例了,但没有明确的 resultMap比如:
  440. </p>
  441. <source><![CDATA[<select id="selectUsers" resultType="map">
  442. select id, username, hashedPassword
  443. from some_table
  444. where id = #{id}
  445. </select>]]></source>
  446. <p>
  447. 这样一个语句简单作用于所有列被自动映射到 HashMap 的键上,这由 resultType 属性
  448. 指定这在很多情况下是有用的,但是 HashMap 不能很好描述一个领域模型那样你的应
  449. 用程序将会使用 JavaBeans POJOs(Plain Old Java Objects,普通 Java 对象)来作为领域
  450. 模型MyBatis 对两者都支持看看下面这个 JavaBean:
  451. </p>
  452. <source><![CDATA[package com.someapp.model;
  453. public class User {
  454. private int id;
  455. private String username;
  456. private String hashedPassword;
  457. public int getId() {
  458. return id;
  459. }
  460. public void setId(int id) {
  461. this.id = id;
  462. }
  463. public String getUsername() {
  464. return username;
  465. }
  466. public void setUsername(String username) {
  467. this.username = username;
  468. }
  469. public String getHashedPassword() {
  470. return hashedPassword;
  471. }
  472. public void setHashedPassword(String hashedPassword) {
  473. this.hashedPassword = hashedPassword;
  474. }
  475. }]]></source>
  476. <p>
  477. 基于 JavaBean 的规范,上面这个类有 3 个属性:id,username hashedPassword这些
  478. select 语句中会精确匹配到列名
  479. </p>
  480. <p>
  481. 这样的一个 JavaBean 可以被映射到结果集,就像映射到 HashMap 一样简单
  482. </p>
  483. <source><![CDATA[<select id="selectUsers" resultType="com.someapp.model.User">
  484. select id, username, hashedPassword
  485. from some_table
  486. where id = #{id}
  487. </select>]]></source>
  488. <p>
  489. 要记住类型别名是你的伙伴使用它们你可以不用输入类的全路径比如:
  490. </p>
  491. <source><![CDATA[<!-- In mybatis-config.xml file -->
  492. <typeAlias type="com.someapp.model.User" alias="User"/>
  493. <!-- In SQL Mapping XML file -->
  494. <select id="selectUsers" resultType="User">
  495. select id, username, hashedPassword
  496. from some_table
  497. where id = #{id}
  498. </select>]]></source>
  499. <p>
  500. 这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,基于属性名来映射列到
  501. JavaBean 的属性上如果列名没有精确匹配,你可以在列名上使用 select 字句的别名(一个
  502. 基本的 SQL 特性)来匹配标签比如:
  503. </p>
  504. <source><![CDATA[<select id="selectUsers" resultType="User">
  505. select
  506. user_id as "id",
  507. user_name as "userName",
  508. hashed_password as "hashedPassword"
  509. from some_table
  510. where id = #{id}
  511. </select>]]></source>
  512. <p>
  513. ResultMap 最优秀的地方你已经了解了很多了,但是你还没有真正的看到一个这些简
  514. 单的示例不需要比你看到的更多东西
  515. 只是出于示例的原因,
  516. 让我们来看看最后一个示例中
  517. 外部的 resultMap 是什么样子的,这也是解决列名不匹配的另外一种方式
  518. </p>
  519. <source><![CDATA[<resultMap id="userResultMap" type="User">
  520. <id property="id" column="user_id" />
  521. <result property="username" column="username"/>
  522. <result property="password" column="password"/>
  523. </resultMap>]]></source>
  524. <p>
  525. 引用它的语句使用 resultMap 属性就行了(注意我们去掉了 resultType 属性)比如:
  526. </p>
  527. <source><![CDATA[<select id="selectUsers" resultMap="userResultMap">
  528. select user_id, user_name, hashed_password
  529. from some_table
  530. where id = #{id}
  531. </select>]]></source>
  532. <p>
  533. 如果世界总是这么简单就好了
  534. </p>
  535. <h4>高级结果映射</h4>
  536. <p>
  537. MyBatis 创建的一个想法:数据库不用永远是你想要的或需要它们是什么样的而我们
  538. 最喜欢的数据库最好是第三范式或 BCNF 模式,但它们有时不是如果可能有一个单独的
  539. 数据库映射,所有应用程序都可以使用它,这是非常好的,但有时也不是结果映射就是
  540. MyBatis 提供处理这个问题的答案
  541. </p>
  542. <p>
  543. 比如,我们如何映射下面这个语句?
  544. </p>
  545. <source><![CDATA[<!-- Very Complex Statement -->
  546. <select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  547. select
  548. B.id as blog_id,
  549. B.title as blog_title,
  550. B.author_id as blog_author_id,
  551. A.id as author_id,
  552. A.username as author_username,
  553. A.password as author_password,
  554. A.email as author_email,
  555. A.bio as author_bio,
  556. A.favourite_section as author_favourite_section,
  557. P.id as post_id,
  558. P.blog_id as post_blog_id,
  559. P.author_id as post_author_id,
  560. P.created_on as post_created_on,
  561. P.section as post_section,
  562. P.subject as post_subject,
  563. P.draft as draft,
  564. P.body as post_body,
  565. C.id as comment_id,
  566. C.post_id as comment_post_id,
  567. C.name as comment_name,
  568. C.comment as comment_text,
  569. T.id as tag_id,
  570. T.name as tag_name
  571. from Blog B
  572. left outer join Author A on B.author_id = A.id
  573. left outer join Post P on B.id = P.blog_id
  574. left outer join Comment C on P.id = C.post_id
  575. left outer join Post_Tag PT on PT.post_id = P.id
  576. left outer join Tag T on PT.tag_id = T.id
  577. where B.id = #{id}
  578. </select>]]></source>
  579. <p>
  580. 你可能想把它映射到一个智能的对象模型,包含一个作者写的博客,有很多的博文,
  581. 篇博文有零条或多条的评论和标签
  582. 下面是一个完整的复杂结果映射例子
  583. (假设作者,
  584. 博客,
  585. 博文,
  586. 评论和标签都是类型的别名) 我们来看看,
  587. 但是不用紧张,
  588. 我们会一步一步来说明
  589. 当天最初它看起来令人生畏,但实际上非常简单
  590. </p>
  591. <source><![CDATA[<!-- Very Complex Result Map -->
  592. <resultMap id="detailedBlogResultMap" type="Blog">
  593. <constructor>
  594. <idArg column="blog_id" javaType="int"/>
  595. </constructor>
  596. <result property="title" column="blog_title"/>
  597. <association property="author" javaType="Author">
  598. <id property="id" column="author_id"/>
  599. <result property="username" column="author_username"/>
  600. <result property="password" column="author_password"/>
  601. <result property="email" column="author_email"/>
  602. <result property="bio" column="author_bio"/>
  603. <result property="favouriteSection" column="author_favourite_section"/>
  604. </association>
  605. <collection property="posts" ofType="Post">
  606. <id property="id" column="post_id"/>
  607. <result property="subject" column="post_subject"/>
  608. <association property="author" javaType="Author"/>
  609. <collection property="comments" ofType="Comment">
  610. <id property="id" column="comment_id"/>
  611. </collection>
  612. <collection property="tags" ofType="Tag" >
  613. <id property="id" column="tag_id"/>
  614. </collection>
  615. <discriminator javaType="int" column="draft">
  616. <case value="1" resultType="DraftPost"/>
  617. </discriminator>
  618. </collection>
  619. </resultMap>]]></source>
  620. <p>
  621. resultMap 元素有很多子元素和一个值得讨论的结构
  622. 下面是 resultMap 元素的概念视图
  623. </p>
  624. <h4>resultMap</h4>
  625. <ul>
  626. <li>
  627. <code>constructor</code> - 类在实例化时,用来注入结果到构造方法中
  628. <ul>
  629. <li><code>idArg</code> - ID 参数;标记结果作为 ID 可以帮助提高整体效能</li>
  630. <li><code>arg</code> - 注入到构造方法的一个普通结果</li>
  631. </ul>
  632. </li>
  633. <li><code>id</code> 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能</li>
  634. <li><code>result</code> 注入到字段或 JavaBean 属性的普通结果</li>
  635. <li>
  636. <code>association</code> 一个复杂的类型关联;许多结果将包成这种类型
  637. <ul>
  638. <li>嵌入结果映射 结果映射自身的关联,或者参考一个
  639. </li>
  640. </ul>
  641. </li>
  642. <li>
  643. <code>collection</code> 复杂类型的集
  644. <ul>
  645. <li>嵌入结果映射 结果映射自身的集,或者参考一个</li>
  646. </ul>
  647. </li>
  648. <li>
  649. <code>discriminator</code> 使用结果值来决定使用哪个结果映射
  650. <ul>
  651. <li>
  652. <code>case</code> 基于某些值的结果映射
  653. <ul>
  654. <li>嵌入结果映射 这种情形结果也映射它本身,因此可以包含很多相
  655. 同的元素,或者它可以参照一个外部的结果映射
  656. </li>
  657. </ul>
  658. </li>
  659. </ul>
  660. </li>
  661. </ul>
  662. <table>
  663. <caption>ResultMap Attributes</caption>
  664. <thead>
  665. <tr>
  666. <th>Attribute</th>
  667. <th>Description</th>
  668. </tr>
  669. </thead>
  670. <tbody>
  671. <tr>
  672. <td><code>id</code></td>
  673. <td>A unique identifier in this namespace that can be used to reference this result map.</td>
  674. </tr>
  675. <tr>
  676. <td><code>type</code></td>
  677. <td>A fully qualified Java class name, or a type alias (see the table above for the list of built-in type aliases).
  678. </td>
  679. </tr>
  680. <tr>
  681. <td><code>autoMapping</code></td>
  682. <td>If present, MyBatis will enable or disable the automapping for this ResultMap.
  683. This attribute overrides the global autoMappingBehavior. Default: unset.
  684. </td>
  685. </tr>
  686. </tbody>
  687. </table>
  688. <p>
  689. <span class="label important">最佳实践</span> 通常逐步建立结果映射单元测试的真正帮助在这里如果你尝试创建
  690. 一次创建一个向上面示例那样的巨大的结果映射,
  691. 那么可能会有错误而且很难去控制它
  692. 来工作开始简单一些,一步一步的发展而且要进行单元测试!使用该框架的缺点是
  693. 它们有时是黑盒(是否可见源代码)
  694. 你确定你实现想要的行为的最好选择是编写单元
  695. 测试它也可以你帮助得到提交时的错误
  696. </p>
  697. <p>
  698. 下面一部分将详细说明每个元素
  699. </p>
  700. <h4>id &amp; result</h4>
  701. <source><![CDATA[<id property="id" column="post_id"/>
  702. <result property="subject" column="post_subject"/>]]></source>
  703. <p>
  704. 这些是结果映射最基本内容id result 都映射一个单独列的值到简单数据类型(字符
  705. ,整型,双精度浮点数,日期等)的单独属性或字段
  706. </p>
  707. <p>
  708. 这两者之间的唯一不同是 id 表示的结果将是当比较对象实例时用到的标识属性这帮
  709. 助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射)
  710. </p>
  711. <p>
  712. 每个都有一些属性:
  713. </p>
  714. <table>
  715. <caption>Id and Result Attributes</caption>
  716. <thead>
  717. <tr>
  718. <th>属性</th>
  719. <th>描述</th>
  720. </tr>
  721. </thead>
  722. <tbody>
  723. <tr>
  724. <td><code>property</code></td>
  725. <td>
  726. 映射到列结果的字段或属性如果匹配的是存在的,和给定名称相同
  727. JavaBeans 的属性,那么就会使用否则 MyBatis 将会寻找给定名称
  728. property
  729. 的字段这两种情形你可以使用通常点式的复杂属性导航比如,
  730. 可以这样映射一些东西:
  731. username
  732. ,或者映射到一些复杂的东西:
  733. address.street.number
  734. </td>
  735. </tr>
  736. <tr>
  737. <td><code>column</code></td>
  738. <td>
  739. 从数据库中得到的列名,或者是列名的重命名标签这也是通常和会
  740. 传递给 resultSet.getString(columnName)方法参数中相同的字符串
  741. </td>
  742. </tr>
  743. <tr>
  744. <td><code>javaType</code></td>
  745. <td>
  746. 一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名
  747. 的列表)
  748. 如果你映射到一个 JavaBean,MyBatis 通常可以断定类型
  749. 然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType
  750. 来保证所需的行为
  751. </td>
  752. </tr>
  753. <tr>
  754. <td><code>jdbcType</code></td>
  755. <td>
  756. 在这个表格之后的所支持的 JDBC 类型列表中的类型JDBC 类型是仅
  757. 仅需要对插入,更新和删除操作可能为空的列进行处理这是 JDBC
  758. jdbcType
  759. 的需要,而不是 MyBatis 如果你直接使用 JDBC 编程,你需要指定
  760. 这个类型-但仅仅对可能为空的值
  761. </td>
  762. </tr>
  763. <tr>
  764. <td><code>typeHandler</code></td>
  765. <td>
  766. 我们在前面讨论过默认的类型处理器使用这个属性,你可以覆盖默
  767. 认的类型处理器这个属性值是类的完全限定名或者是一个类型处理
  768. 器的实现,或者是类型别名
  769. </td>
  770. </tr>
  771. </tbody>
  772. </table>
  773. <h4>支持的 JDBC 类型</h4>
  774. <p>
  775. 为了未来的参考,MyBatis 通过包含的 jdbcType 枚举型,支持下面的 JDBC 类型
  776. </p>
  777. <table>
  778. <tr>
  779. <td><code>BIT</code></td>
  780. <td><code>FLOAT</code></td>
  781. <td><code>CHAR</code></td>
  782. <td><code>TIMESTAMP</code></td>
  783. <td><code>OTHER</code></td>
  784. <td><code>UNDEFINED</code></td>
  785. </tr>
  786. <tr>
  787. <td><code>TINYINT</code></td>
  788. <td><code>REAL</code></td>
  789. <td><code>VARCHAR</code></td>
  790. <td><code>BINARY</code></td>
  791. <td><code>BLOG</code></td>
  792. <td><code>NVARCHAR</code></td>
  793. </tr>
  794. <tr>
  795. <td><code>SMALLINT</code></td>
  796. <td><code>DOUBLE</code></td>
  797. <td><code>LONGVARCHAR</code></td>
  798. <td><code>VARBINARY</code></td>
  799. <td><code>CLOB</code></td>
  800. <td><code>NCHAR</code></td>
  801. </tr>
  802. <tr>
  803. <td><code>INTEGER</code></td>
  804. <td><code>NUMERIC</code></td>
  805. <td><code>DATE</code></td>
  806. <td><code>LONGVARBINARY</code></td>
  807. <td><code>BOOLEAN</code></td>
  808. <td><code>NCLOB</code></td>
  809. </tr>
  810. <tr>
  811. <td><code>BIGINT</code></td>
  812. <td><code>DECIMAL</code></td>
  813. <td><code>TIME</code></td>
  814. <td><code>NULL</code></td>
  815. <td><code>CURSOR</code></td>
  816. <td><code>ARRAY</code></td>
  817. </tr>
  818. </table>
  819. <h4>构造方法</h4>
  820. <source><![CDATA[<constructor>
  821. <idArg column="id" javaType="int"/>
  822. <arg column="username" javaType="String"/>
  823. </constructor>]]></source>
  824. <p>
  825. 对于大多数数据传输对象(Data Transfer Object,DTO)类型,属性可以起作用,而且像
  826. 你绝大多数的领域模型,
  827. 指令也许是你想使用一成不变的类的地方
  828. 通常包含引用或查询数
  829. 据的表很少或基本不变的话对一成不变的类来说是合适的
  830. 构造方法注入允许你在初始化时
  831. 为类设置属性的值,而不用暴露出公有方法MyBatis 也支持私有属性和私有 JavaBeans
  832. 性来达到这个目的,但是一些人更青睐构造方法注入构造方法元素支持这个
  833. </p>
  834. <p>
  835. 看看下面这个构造方法:
  836. </p>
  837. <source><![CDATA[public class User {
  838. //...
  839. public User(int id, String username) {
  840. //...
  841. }
  842. //...
  843. }]]></source>
  844. <p>
  845. 为了向这个构造方法中注入结果,MyBatis 需要通过它的参数的类型来标识构造方法
  846. Java 没有自查(反射)参数名的方法所以当创建一个构造方法元素时,保证参数是按顺序
  847. 排列的,而且数据类型也是确定的
  848. </p>
  849. <source><![CDATA[<constructor>
  850. <idArg column="id" javaType="int"/>
  851. <arg column="username" javaType="String"/>
  852. </constructor>]]></source>
  853. <p>
  854. 剩余的属性和规则和固定的 id result 元素是相同的
  855. </p>
  856. <table>
  857. <thead>
  858. <tr>
  859. <th>属性</th>
  860. <th>描述</th>
  861. </tr>
  862. </thead>
  863. <tbody>
  864. <tr>
  865. <td><code>column</code></td>
  866. <td>
  867. 来自数据库的类名,或重命名的列标签这和通常传递给
  868. resultSet.getString(columnName)方法的字符串是相同的
  869. </td>
  870. </tr>
  871. <tr>
  872. <td><code>javaType</code></td>
  873. <td>
  874. 一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名的列表)
  875. 如果你映射到一个 JavaBean,MyBatis 通常可以断定类型然而,
  876. 果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证所需的
  877. 行为
  878. </td>
  879. </tr>
  880. <tr>
  881. <td><code>jdbcType</code></td>
  882. <td>
  883. 在这个表格之前的所支持的 JDBC 类型列表中的类型JDBC 类型是仅仅
  884. 需要对插入,
  885. 更新和删除操作可能为空的列进行处理这是 JDBC 的需要,
  886. jdbcType
  887. 而不是 MyBatis 如果你直接使用 JDBC 编程,你需要指定这个类型-
  888. 仅仅对可能为空的值
  889. </td>
  890. </tr>
  891. <tr>
  892. <td><code>typeHandler</code></td>
  893. <td>
  894. 我们在前面讨论过默认的类型处理器使用这个属性,你可以覆盖默认的
  895. 类型处理器
  896. 这个属性值是类的完全限定名或者是一个类型处理器的实现,
  897. 或者是类型别名
  898. </td>
  899. </tr>
  900. <tr>
  901. <td><code>select</code></td>
  902. <td>
  903. The ID of another mapped statement that will load the complex type required by this
  904. property mapping. The values retrieved from columns specified in the column attribute
  905. will be passed to the target select statement as parameters. See the Association element
  906. for more.
  907. </td>
  908. </tr>
  909. <tr>
  910. <td><code>resultMap</code></td>
  911. <td>
  912. This is the ID of a ResultMap that can map the nested results of this argument into an
  913. appropriate object graph. This is an alternative to using a call to another select
  914. statement. It allows you to join multiple tables together into a single <code>ResultSet</code>. Such
  915. a <code>ResultSet</code> will contain duplicated, repeating groups of data that needs to be
  916. decomposed and mapped properly to a nested object graph. To facilitate this, MyBatis
  917. lets you "chain" result maps together, to deal with the nested results. See the
  918. Association element below for more.
  919. </td>
  920. </tr>
  921. </tbody>
  922. </table>
  923. <h4><code>关联</code></h4>
  924. <source><![CDATA[<association property="author" column="blog_author_id" javaType="Author">
  925. <id property="id" column="author_id"/>
  926. <result property="username" column="author_username"/>
  927. </association>]]></source>
  928. <p>
  929. 关联元素处理有一个类型的关系比如,在我们的示例中,一个博客有一个用户
  930. 关联映射就工作于这种结果之上你指定了目标属性,来获取值的列,属性的 java 类型(
  931. 多情况下 MyBatis 可以自己算出来)
  932. ,如果需要的话还有 jdbc 类型,如果你想覆盖或获取的
  933. 结果值还需要类型控制器
  934. </p>
  935. <p>
  936. 关联中不同的是你需要告诉 MyBatis 如何加载关联MyBatis 在这方面会有两种不同的
  937. 方式:
  938. </p>
  939. <ul>
  940. <li>
  941. 嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型
  942. </li>
  943. <li>
  944. 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集首先,然让我们来查看这个元素的属性所有的你都会看到,它和普通的只由 select
  945. </li>
  946. </ul>
  947. <p>
  948. resultMap 属性的结果映射不同
  949. </p>
  950. <table>
  951. <thead>
  952. <tr>
  953. <th>属性</th>
  954. <th>描述</th>
  955. </tr>
  956. </thead>
  957. <tbody>
  958. <tr>
  959. <td><code>property</code></td>
  960. <td>
  961. 映射到列结果的字段或属性如果匹配的是存在的,和给定名称相同的
  962. property
  963. JavaBeans 的属性,
  964. 那么就会使用
  965. 否则 MyBatis 将会寻找给定名称的字段
  966. 这两种情形你可以使用通常点式的复杂属性导航比如,你可以这样映射
  967. 西 : username , 西 :
  968. address.street.number
  969. </td>
  970. </tr>
  971. <tr>
  972. <td><code>javaType</code></td>
  973. <td>
  974. 一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名的列
  975. )
  976. 如果你映射到一个 JavaBean,MyBatis 通常可以断定类型然而,
  977. javaType
  978. 果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证所需的
  979. 行为
  980. </td>
  981. </tr>
  982. <tr>
  983. <td><code>jdbcType</code></td>
  984. <td>
  985. 在这个表格之前的所支持的 JDBC 类型列表中的类型JDBC 类型是仅仅
  986. 需要对插入,
  987. 更新和删除操作可能为空的列进行处理这是 JDBC 的需要,
  988. jdbcType
  989. 而不是 MyBatis 如果你直接使用 JDBC 编程,你需要指定这个类型-
  990. 仅仅对可能为空的值
  991. </td>
  992. </tr>
  993. <tr>
  994. <td><code>typeHandler</code></td>
  995. <td>
  996. 我们在前面讨论过默认的类型处理器使用这个属性,你可以覆盖默认的
  997. typeHandler
  998. 类型处理器
  999. 这个属性值是类的完全限定名或者是一个类型处理器的实现,
  1000. 或者是类型别名
  1001. </td>
  1002. </tr>
  1003. </tbody>
  1004. </table>
  1005. <h4>关联的嵌套查询</h4>
  1006. <table>
  1007. <thead>
  1008. <tr>
  1009. <th>属性</th>
  1010. <th>描述</th>
  1011. </tr>
  1012. </thead>
  1013. <tbody>
  1014. <tr>
  1015. <td><code>column</code></td>
  1016. <td>
  1017. 来自数据库的类名,或重命名的列标签这和通常传递给
  1018. resultSet.getString(columnName)方法的字符串是相同的
  1019. column
  1020. : , column=
  1021. {prop1=col1,prop2=col2} 这种语法来传递给嵌套查询语 这会引起
  1022. prop1 prop2 以参数对象形式来设置给目标嵌套查询语句
  1023. </td>
  1024. </tr>
  1025. <tr>
  1026. <td><code>select</code></td>
  1027. <td>
  1028. 另外一个映射语句的 ID,可以加载这个属性映射需要的复杂类型获取的
  1029. 在列属性中指定的列的值将被传递给目标 select 语句作为参数表格后面
  1030. 有一个详细的示例
  1031. select
  1032. : , column=
  1033. {prop1=col1,prop2=col2} 这种语法来传递给嵌套查询语 这会引起
  1034. prop1 prop2 以参数对象形式来设置给目标嵌套查询语句
  1035. </td>
  1036. </tr>
  1037. <tr>
  1038. <td><code>fetchType</code></td>
  1039. <td>
  1040. Optional. Valid values are <code>lazy</code> and <code>eager</code>. If present, it supersedes
  1041. the global configuration parameter <code>lazyLoadingEnabled</code> for this mapping.
  1042. </td>
  1043. </tr>
  1044. </tbody>
  1045. </table>
  1046. <p>
  1047. 示例:
  1048. </p>
  1049. <source><![CDATA[<resultMap id="blogResult" type="Blog">
  1050. <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
  1051. </resultMap>
  1052. <select id="selectBlog" resultMap="blogResult">
  1053. SELECT * FROM BLOG WHERE ID = #{id}
  1054. </select>
  1055. <select id="selectAuthor" resultType="Author">
  1056. SELECT * FROM AUTHOR WHERE ID = #{id}
  1057. </select>]]></source>
  1058. <p>
  1059. 我们有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描
  1060. 述了selectAuthor语句应该被用来加载它的 author 属性
  1061. </p>
  1062. <p>
  1063. 其他所有的属性将会被自动加载,假设它们的列和属性名相匹配
  1064. </p>
  1065. <p>
  1066. 这种方式很简单,
  1067. 但是对于大型数据集合和列表将不会表现很好
  1068. 问题就是我们熟知的
  1069. N+1 查询问题概括地讲,N+1 查询问题可以是这样引起的:
  1070. </p>
  1071. <ul>
  1072. <li>你执行了一个单独的 SQL 语句来获取结果列表(就是+1)</li>
  1073. <li>对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是N)
  1074. </li>
  1075. </ul>
  1076. <p>
  1077. 这个问题会导致成百上千的 SQL 语句被执行这通常不是期望的
  1078. </p>
  1079. <p>
  1080. MyBatis 能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消
  1081. 然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加
  1082. ,这样的行为可能是很糟糕的
  1083. </p>
  1084. <p>
  1085. 所以还有另外一种方法
  1086. </p>
  1087. <h4>关联的嵌套结果</h4>
  1088. <table>
  1089. <thead>
  1090. <tr>
  1091. <th>属性</th>
  1092. <th>描述</th>
  1093. </tr>
  1094. </thead>
  1095. <tbody>
  1096. <tr>
  1097. <td><code>resultMap</code></td>
  1098. <td>
  1099. 这是结果映射的 ID,可以映射关联的嵌套结果到一个合适的对象图中
  1100. 是一种替代方法来调用另外一个查询语句这允许你联合多个表来合成到
  1101. resultMap
  1102. 一个单独的结果集

Large files files are truncated, but you can click here to view the full file