# Mybatis使用之查詢詳解
### 一:簡介
?????? 此篇主要知識點:
??????1、sql語句塊
??????2、select標簽屬性
??????3、ResultMap 標簽配置
??????4、一對一關聯
??????5、一對多關聯
??????6、多對多關聯
????? 7、嵌套查詢
### 二:SQL語句塊
### ???????2.1 作用
?????????????SQL元素可以被用來定義可重用的SQL 代碼段,可以包含在其他語句中。比如在項目中常常做的分頁查詢、分別需要兩條SQL語句、一條是查詢所有具體記錄信息、另一條需要查詢記錄數、而兩條語句的where條件是一樣的。這種類似情況就可以使用SQL語句塊來簡化配置信息。
### ???????2.2 實例
?????????????2.2.1 SQL語句定義:
?????
~~~
<sql id="queryColumns"> id, username, password </sql>
~~~
?????????????2.2.2 使用:
~~~
<select id="queryAuthor" parameterType="int" resultType="author">
SELECT
<include refid="queryColumns"/>
FROM author
WHERE id = #{id}
</select>
~~~
### 三:select標簽屬性
### ???????3.1 標簽屬性集合:
~~~
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
~~~
### ???????3.2具體意義:
?????????????參見補充部分。
### 四:ResultMap 標簽配置
### ???????4.1 介紹
?????????????resultMap 元素是MyBatis 中最重要最強大的元素。它就是讓你遠離90%的需要從結果集中取出數據的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事情。事實上, 編寫相似于對復雜語句聯合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設計就是簡單語句不需要明確的結果映射,而很多復雜語句確實需要描述它們的關系。
### ???????4.2 ResultMap 與ResultType的區別
?????????????MyBatis中在查詢進行select映射的時候,返回類型可以用resultType,也可以用resultMap。resultType是直接表示返回類型的,而resultMap則是對外部ResultMap的引用但是resultType跟resultMap不能同時存在。
在MyBatis進行查詢映射的時候,其實查詢出來的每一個屬性都是放在一個對應的Map里面的,其中鍵是屬性名,值則是其對應的值。當提供的返回類型屬性是resultType的時候,MyBatis會將Map里面的鍵值對取出賦給resultType所指定的對象對應的屬性。
所以其實MyBatis的每一個查詢映射的返回類型都是ResultMap,只是當我們提供的返回類型屬性是resultType的時候,MyBatis對自動的給我們把對應的值賦給resultType所指定對象的屬性,而當我們提供的返回類型是resultMap的時候,Mybatis就會根據我們配置的信息做映射
### ???????4.3 標簽屬性
~~~
<resultMap id="resultMapId"
type="JavaBean"
autoMapping="false"
extends=""/>
~~~
### ???????4.4 標簽體
?????????????ResultMap的主要組成部分、并且標簽體之間可以相互嵌套、來表示更復雜的JavaBean。具體的使用到對應的標簽體再說明其作用與標簽屬性的配置及意義。
?????????????下面是其標簽體簽名:
~~~
<constructor>
<idArg/>
<arg/>
</constructor>
<id property="" column="" javaType="" jdbcType="" typeHandler=""/>
<result typeHandler="" jdbcType="" javaType="" column="" property=""/>
<association property=""/>
<collection property=""/>
<discriminator javaType="">
<case value=""/>
</discriminator>
~~~
### 五:簡單對象select映射
### ??????? 5.1 ResultType類型返回值的表示方式:
???????????
??????????? 因為在前面提到過、加載Mybatis總配置文件的時候會自動掃描指定包下面的類、并且用類名首字母小寫作為名稱作為其別名(TypeAliases)、這樣我們就不必在select的resultType指定JavaBean的全限定名稱了。select語句如下即可:
~~~
<select id="getAllAuthors" resultType="author">
SELECT
t.id,
t.username,
t.password,
t.email,
t.bio,
t.favourite_section favouriteSection
FROM author t
</select>
~~~
### ??????? 5.2 ResultMap類型返回值的表示方式:
????????????
???????????? 5.2.1 配置ResultMap
~~~
<resultMap id="author" type="author">
<id property="id" column="author_id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="email" column="email"/>
<result property="bio" column="bio"/>
<result property="favouriteSection" column="favouriteSection"/>
</resultMap>
~~~
???????????? 5.2.2 將select標簽的ResultMap屬性值設置為上面ResultMap標簽的id、達到映射效果
~~~
<select id="getAllAuthors" resultMap="author">
SELECT
t.id,
t.username,
t.password,
t.email,
t.bio,
t.favourite_section favouriteSection
FROM author t
</select>
~~~
???????????? 5.2.3 當前ResultMap中 id result子表簽作用及屬性意義
????????????
### 六:一對一關聯
?????
### ????? 6.1 一對一場景
????? 以Blog為例、從[《Mybatis使用之環境搭建》](http://blog.csdn.net/crave_shy/article/details/45825631)中知道Blog與Author是一對一關系、這里是在Blog中關聯了Author信息。其他的先不管。如何查詢Blog信息、要求是除基本信息外還包含作者完整信息
????? 6.1.1 ResultMap配置一:
~~~
<resultMap id="oneToOneBlog" type="blog">
<id property="id" column="blog_id"/>
<result property="title" column="title"/>
<!-- 可以使用resultMap屬性指向其他映射文件已經定義好的resultMap -->
<association property="author" resultMap="org.alien.mybatis.samples.mapper.AuthorMapper.author"/>
</resultMap>
~~~
????? 6.1.2 ResultMap配置二:
~~~
<resultMap id="oneToOneBlog" type="blog">
<id property="id" column="blog_id"/>
<result property="title" column="title"/>
<!-- 也可以在此內部定義指向Author類的映射、此種定義不能重用 -->
<association property="author" javaType="author">
<id property="id" column="author_id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="email" column="email"/>
<result property="bio" column="bio"/>
<result property="favouriteSection" column="favouriteSection"/>
</association>
</resultMap>
~~~
????? 6.1.3查詢語句:
~~~
<select id="getBlogOneToOne" resultMap="oneToOneBlog">
SELECT
t1.id blog_id,
t1.title,
t2.id author_id,
t2.username,
t2.password,
t2.email,
t2.bio,
t2.favourite_section favouriteSection
FROM blog t1, author t2
WHERE t1.author_id = t2.id
</select>
~~~
????? 6.1.4 association標簽屬性以及標簽體
???? ??????屬性:
?????
### 七:一對多關聯
?????
### ????? 7.1 一對多場景
????? 以Blog為例、從[《Mybatis使用之環境搭建》](http://blog.csdn.net/crave_shy/article/details/45825631)中知道Blog與Post是一對多關系、這里是在Blog中有一個集合存放類型為Post的List。
????? 7.1.1 ResultMap配置一:
~~~
<resultMap id="oneToMany" type="blog">
<id property="id" column="blog_id" javaType="int"/>
<result property="title" column="title" javaType="string"/>
<collection property="posts" ofType="post">
<id property="id" column="post_id"/>
<result property="section" column="section"/>
</collection>
</resultMap>
~~~
????? 7.1.2 ResultMap配置二:
~~~
<resultMap id="oneToManyResultMap" type="blog">
<id property="id" column="blog_id" javaType="int"/>
<result property="title" column="title" javaType="string"/>
<collection property="posts" ofType="post" resultMap="org.alien.mybatis.samples.mapper.PostMapper.post"/>
</resultMap>
~~~
????? 7.1.3查詢語句:
~~~
<!--<select id="getBlogWithPosts" resultMap="oneToMany">-->
<select id="getBlogWithPosts" resultMap="oneToManyResultMap">
SELECT
t1.id blog_id,
t1.title,
t2.id post_id,
t2.section
FROM blog t1 LEFT OUTER JOIN post t2 ON t1.id = t2.blog_id WHERE t1.id = 1
</select>
~~~
?????
???? 7.1.4 collection標簽屬性:
????? “ofType”屬性。這個屬性用來區分JavaBean(或字段)屬性類型和集合包含的類型(類型明確下也可以省略)。比如:
~~~
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
讀作: “在 Post 類型的 ArrayList 中的 posts 的集合。”
javaType 屬性是不需要的,因為 MyBatis 在很多情況下會為你算出來。所以你可以縮短 寫法:
<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
~~~
### 八:多對多關聯
?????? 多對多關聯可以簡化為單方面一對多關聯。可以參見一對多關聯的方式實現。
### 九:嵌套關聯
### ????? 9.1 一對多場景
????? 以Blog為例、從[《Mybatis使用之環境搭建》](http://blog.csdn.net/crave_shy/article/details/45825631)中知道Blog與Post是一對多關系、Post與PostComment(文章評論)Tag(文章標簽)是一對多、當在查詢Blog屬性時、關聯的Post屬性一并查出來、同時PostComment和Tag屬性關聯出來。
????? 9.1.1 ResultMap配置:
~~~
<resultMap id="oneToManyNested" type="blog">
<id property="id" column="blog_id" javaType="int"/>
<result property="title" column="title" javaType="string"/>
<collection property="posts" ofType="post">
<id property="id" column="post_id"/>
<result property="section" column="section"/>
<collection property="comments" resultMap="org.alien.mybatis.samples.mapper.PostCommentMapper.postComment"/>
<collection property="tags" ofType="tag">
<id property="id" column="tag_id"/>
<result property="name" column="tag_name"/>
</collection>
</collection>
</resultMap>
~~~
????? 9.1.2 查詢語句:
~~~
<select id="getBlogWithPostsNested" resultMap="oneToManyNested">
SELECT
t1.id blog_id,
t1.title,
t2.id post_id,
t2.section,
t3.id post_comment_id,
t3.name post_comment_name,
t3.comment_text post_comment_text,
t5.id tag_id,
t5.name tag_name
FROM blog t1 LEFT OUTER JOIN post t2 ON t1.id = t2.blog_id
LEFT OUTER JOIN post_comment t3 ON t2.id = t3.post_id
LEFT OUTER JOIN post_tag t4 ON t2.id = t4.post_id
LEFT OUTER JOIN tag t5 ON t4.tag_id = t5.id WHERE t1.id = 1
</select>
~~~
### 十:緩存
??????MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3中的緩存實現的很多改進都已經實現了,使得它更加強大而且易于配置。
默認情況下是沒有開啟緩存的,除了局部的 session 緩存,可以增強變現而且處理循環依賴也是必須的。要開啟二級緩存,你需要在你的 SQL 映射文件中添加一行:
~~~
<cache/>
~~~
字面上看就是這樣。這個簡單語句的效果如下:
- 映射語句文件中的所有 select 語句將會被緩存。
- 映射語句文件中的所有 insert,update 和 delete 語句會刷新緩存。
- 緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
- 根據時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新。
- 緩存會存儲列表集合或對象(無論查詢方法返回什么)的 1024 個引用。
- 緩存會被視為是 read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而且可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。
所有的這些屬性都可以通過緩存元素的屬性來修改。比如:
~~~
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
~~~
這個更高級的配置創建了一個 FIFO 緩存,并每隔 60 秒刷新,存數結果對象或列表的512 個引用,而且返回的對象被認為是只讀的,因此在不同線程中的調用者之間修改它們會導致沖突。
可用的收回策略有:
- LRU – 最近最少使用的:移除最長時間不被使用的對象。
- FIFO – 先進先出:按對象進入緩存的順序來移除它們。
- SOFT – 軟引用:移除基于垃圾回收器狀態和軟引用規則的對象。
- WEAK – 弱引用:更積極地移除基于垃圾收集器狀態和弱引用規則的對象。
默認的是 LRU。
flushInterval(刷新間隔)可以被設置為任意的正整數,而且它們代表一個合理的毫秒形式的時間段。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。
size(引用數目)可以被設置為任意正整數,要記住你緩存的對象數目和你運行環境的可用內存資源數目。默認值是 1024。
readOnly(只讀)屬性可以被設置為 true 或 false。只讀的緩存會給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。可讀寫的緩存會返回緩存對象的拷貝(通過序列化)。這會慢一些,但是安全,因此默認是 false。
這里暫時沒有自定義緩存、后面會有專門關于緩存的記錄。
### 補充:
? ? ? 更多內容:[Mybatis 目錄](http://blog.csdn.net/crave_shy/article/details/45825599)
?????? github地址:https://github.com/andyChenHuaYing/scattered-items/tree/master/items-mybatis
?????? 源碼下載地址:http://download.csdn.net/detail/chenghuaying/8713311
????? select標簽屬性對應意義:

