文章內(nèi)容來源自官方文檔喉酌,后期會加入例子說明以及使用中的細(xì)節(jié)問題孙蒙。
首先是一張大又全:
一飞蹂、Mapper映射文件說明
1、完整的Mapper映射文件結(jié)構(gòu)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.dao.×××Mapper">
<!--下面是映射文件頂級元素肃廓,
在實際使用中智厌,官方建議按照這個順序來進行定義-->
<cache>...</cache>
<cache-ref />
<resultMap >...</resultMap>
<sql >...</sql>
<insert >...</insert>
<update >...</update>
<delete >...</delete>
<select >...</select>
</mapper>
其中:
- mapper元素中的namespace是用于綁定Dao接口的,當(dāng)通過namespace綁定接口后盲赊,就不必寫接口實現(xiàn)類铣鹏,mybatis會通過該綁定自動找到對應(yīng)要執(zhí)行的SQL語句,生成對應(yīng)的接口實現(xiàn)方法哀蘑。
- 頂級元素說明:
cache – 設(shè)置命名空間的緩存配置吝沫。
cache-ref –引用其他命名空間緩存配置。
resultMap – 是最復(fù)雜也是最強大的元素递礼,用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象惨险。
sql – 可被其他語句引用的可重用語句塊。
insert – 映射插入語句
update – 映射更新語句
delete – 映射刪除語句
select – 映射查詢語句
2脊髓、select元素
- 元素屬性
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
屬性 | 描述 |
---|---|
id | 在命名空間中唯一的標(biāo)識符辫愉,可以被用來引用這條語句。 |
parameterType | 將會傳入這條語句的參數(shù)類的完全限定名或別名将硝。這個屬性是可選的恭朗,因為 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數(shù),默認(rèn)值為 unset依疼。 |
parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法痰腮。使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
resultType | 從這條語句中返回的期望類型的類的完全限定名或別名律罢。注意如果是集合情形膀值,那應(yīng)該是集合可以包含的類型,而不能是集合本身误辑。使用 resultType 或 resultMap沧踏,但不能同時使用。 |
resultMap | 外部 resultMap 的命名引用巾钉。結(jié)果集的映射是 MyBatis 最強大的特性翘狱,對其有一個很好的理解的話,許多復(fù)雜映射的情形都能迎刃而解砰苍。使用 resultMap 或 resultType潦匈,但不能同時使用阱高。 |
flushCache | 將其設(shè)置為 true,任何時候只要語句被調(diào)用茬缩,都會導(dǎo)致本地緩存和二級緩存都會被清空赤惊,默認(rèn)值:false。 |
useCache | 將其設(shè)置為 true寒屯,將會導(dǎo)致本條語句的結(jié)果被二級緩存,默認(rèn)值:對 select 元素為 true黍少。 |
timeout | 這個設(shè)置是在拋出異常之前寡夹,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)。默認(rèn)值為 unset(依賴驅(qū)動)厂置。 |
fetchSize | 這是嘗試影響驅(qū)動程序每次批量返回的結(jié)果行數(shù)和這個設(shè)置值相等菩掏。默認(rèn)值為 unset(依賴驅(qū)動)。 |
statementType | STATEMENT昵济,PREPARED 或 CALLABLE 的一個智绸。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement访忿,默認(rèn)值:PREPARED瞧栗。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個海铆,默認(rèn)值為 unset (依賴驅(qū)動)迹恐。 |
databaseId | 如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語句卧斟;如果帶或者不帶的語句都有殴边,則不帶的會被忽略。 |
resultOrdered | 這個設(shè)置僅針對嵌套結(jié)果 select 語句適用:如果為 true珍语,就是假設(shè)包含了嵌套結(jié)果集或是分組了锤岸,這樣的話當(dāng)返回一個主結(jié)果行的時候,就不會發(fā)生有對前面結(jié)果集的引用的情況板乙。這就使得在獲取嵌套的結(jié)果集的時候不至于導(dǎo)致內(nèi)存不夠用是偷。默認(rèn)值:false。 |
resultSets | 這個設(shè)置僅對多結(jié)果集的情況適用募逞,它將列出語句執(zhí)行后返回的結(jié)果集并每個結(jié)果集給一個名稱晓猛,名稱是逗號分隔的。 |
3凡辱、insert, update 和 delete
數(shù)據(jù)變更語句 insert戒职,update 和 delete 的實現(xiàn)非常接近:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
屬性 | 描述 |
---|---|
id | 命名空間中的唯一標(biāo)識符,可被用來代表這條語句透乾。 |
parameterType | 將要傳入語句的參數(shù)的完全限定類名或別名洪燥。這個屬性是可選的磕秤,因為 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數(shù),默認(rèn)值為 unset捧韵。 |
flushCache | 將其設(shè)置為 true市咆,任何時候只要語句被調(diào)用,都會導(dǎo)致本地緩存和二級緩存都會被清空再来,默認(rèn)值:true(對應(yīng)插入蒙兰、更新和刪除語句)。 |
timeout | 這個設(shè)置是在拋出異常之前芒篷,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)搜变。默認(rèn)值為 unset(依賴驅(qū)動)。 |
statementType | STATEMENT针炉,PREPARED 或 CALLABLE 的一個挠他。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement篡帕,默認(rèn)值:PREPARED殖侵。 |
useGeneratedKeys | (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數(shù)據(jù)庫內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫管理系統(tǒng)的自動遞增字段),默認(rèn)值:false镰烧。 |
keyProperty | (僅對 insert 和 update 有用)唯一標(biāo)記一個屬性拢军,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設(shè)置它的鍵值,默認(rèn):unset怔鳖。如果希望得到多個生成的列朴沿,也可以是逗號分隔的屬性名稱列表。 |
keyColumn | (僅對 insert 和 update 有用)通過生成的鍵值設(shè)置表中的列名败砂,這個設(shè)置僅在某些數(shù)據(jù)庫(像 PostgreSQL)是必須的赌渣,當(dāng)主鍵列不是表中的第一列的時候需要設(shè)置。如果希望得到多個生成的列昌犹,也可以是逗號分隔的屬性名稱列表坚芜。 |
databaseId | 如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語句斜姥;如果帶或者不帶的語句都有鸿竖,則不帶的會被忽略。 |
- 下面是 insert铸敏,update 和 delete 語句的一些示例:
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
- 插入時處理主鍵的生成
首先缚忧,如果你的數(shù)據(jù)庫支持自動生成主鍵的字段(比如 MySQL 和 SQL Server),那么你可以設(shè)置 useGeneratedKeys=”true”杈笔,然后再把 keyProperty 設(shè)置到目標(biāo)屬性上就OK了闪水。例如,如果上面的 Author 表已經(jīng)對 id 使用了自動生成的列類型蒙具,那么語句可以修改為:
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
如果你的數(shù)據(jù)庫還支持多行插入, 你也可以傳入一個Authors數(shù)組或集合球榆,并返回自動生成的主鍵朽肥。
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
對于不支持自動生成類型的數(shù)據(jù)庫或可能不支持自動生成主鍵 JDBC 驅(qū)動來說,MyBatis 有另外一種方法來生成主鍵持钉。
這里有一個簡單(甚至很傻)的示例衡招,它可以生成一個隨機 ID(你最好不要這么做,但這里展示了 MyBatis 處理問題的靈活性及其所關(guān)心的廣度):
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
</insert>
在上面的示例中每强,selectKey 元素將會首先運行始腾,Author 的 id 會被設(shè)置,然后插入語句會被調(diào)用空执。這給你了一個和數(shù)據(jù)庫中來處理自動生成的主鍵類似的行為浪箭,避免了使 Java 代碼變得復(fù)雜。
</br>selectKey 元素描述如下:
<selectKey
keyProperty="id"
resultType="int"
order="BEFORE"
statementType="PREPARED">
</selectKey>
屬性 | 描述 |
---|---|
keyProperty | selectKey 語句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性脆烟。如果希望得到多個生成的列山林,也可以是逗號分隔的屬性名稱列表房待。 |
keyColumn | 匹配屬性的返回結(jié)果集中的列名稱邢羔。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表桑孩。 |
resultType | 結(jié)果的類型拜鹤。MyBatis 通常可以推算出來流椒,但是為了更加確定寫上也不會有什么問題敏簿。MyBatis 允許任何簡單類型用作主鍵的類型,包括字符串宣虾。如果希望作用于多個生成的列惯裕,則可以使用一個包含期望屬性的 Object 或一個 Map。 |
order | 這可以被設(shè)置為 BEFORE 或 AFTER绣硝。如果設(shè)置為 BEFORE蜻势,那么它會首先選擇主鍵,設(shè)置 keyProperty 然后執(zhí)行插入語句鹉胖。如果設(shè)置為 AFTER握玛,那么先執(zhí)行插入語句,然后是 selectKey 元素 - 這和像 Oracle 的數(shù)據(jù)庫相似甫菠,在插入語句內(nèi)部可能有嵌入索引調(diào)用挠铲。 |
statementType | 與前面相同,MyBatis 支持 STATEMENT寂诱,PREPARED 和 CALLABLE 語句的映射類型拂苹,分別代表 PreparedStatement 和 CallableStatement 類型。 |
4痰洒、sql元素
這個元素可以被用來定義可重用的 SQL 代碼段醋寝,可以包含在其他語句中搞挣。它可以被靜態(tài)地(在加載參數(shù)) 參數(shù)化. 不同的屬性值通過包含的實例變化. 比如:
<sql id="userColumns">
${alias}.id,${alias}.username,${alias}.password
</sql>
這個 SQL 片段可以被包含在其他語句中,例如:
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
屬性值可以用于包含的refid屬性或者包含的字句里面的屬性值音羞,例如:
<sql id="sometable">
${prefix}Table
</sql>
<sql id="someinclude">
from
<include refid="${include_target}"/>
</sql>
<select id="select" resultType="map">
select
field1, field2, field3
<include refid="someinclude">
<property name="prefix" value="Some"/>
<property name="include_target" value="sometable"/>
</include>
</select>
5囱桨、Result Maps
resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠(yuǎn)離 90%的需要從結(jié)果 集中取出數(shù)據(jù)的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情嗅绰。 事實上, 編寫相似于對復(fù)雜語句聯(lián)合映射這些等同的代碼, 也許可以跨過上千行的代碼舍肠。 ResultMap 的設(shè)計就是簡單語句不需要明確的結(jié)果映射,而很多復(fù)雜語句確實需要描述它們 的關(guān)系。
對于下面這個 JavaBean:
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
那么窘面,可以這樣來使用resultMap翠语。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
6、一個非常復(fù)雜的映射例子
如何映射下面這個語句?
描述:查詢一個作者寫的博客财边,博客里包含很多博文肌括,每篇博文有零條或多條的評論和標(biāo)簽。
<!-- Very Complex Statement -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio,
A.favourite_section as author_favourite_section,
P.id as post_id,
P.blog_id as post_blog_id,
P.author_id as post_author_id,
P.created_on as post_created_on,
P.section as post_section,
P.subject as post_subject,
P.draft as draft,
P.body as post_body,
C.id as comment_id,
C.post_id as comment_post_id,
C.name as comment_name,
C.comment as comment_text,
T.id as tag_id,
T.name as tag_name
from Blog B
left outer join Author A on B.author_id = A.id
left outer join Post P on B.id = P.blog_id
left outer join Comment C on P.id = C.post_id
left outer join Post_Tag PT on PT.post_id = P.id
left outer join Tag T on PT.tag_id = T.id
where B.id = #{id}
</select>
那么酣难,可以這么來寫 (假設(shè)作者, 博客, 博文, 評論和標(biāo)簽都是類型的別名) :
<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
(待補充)
6谍夭、緩存
MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實現(xiàn)的很多改進都已經(jīng)實現(xiàn)了,使得它更加強大而且易于配置憨募。
默認(rèn)情況下是沒有開啟緩存的,除了局部的 session 緩存,可以增強變現(xiàn)而且處理循環(huán) 依賴也是必須的紧索。要開啟二級緩存,你需要在你的 SQL 映射文件中添加一行:
<cache/>
字面上看就是這樣。這個簡單語句的效果如下:
映射語句文件中的所有 select 語句將會被緩存菜谣。
映射語句文件中的所有 insert,update 和 delete 語句會刷新緩存珠漂。
緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
根據(jù)時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新尾膊。
緩存會存儲列表集合或?qū)ο?無論查詢方法返回什么)的 1024 個引用媳危。
緩存會被視為是 read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
所有的這些屬性都可以通過緩存元素的屬性來修改冈敛。比如:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
這個更高級的配置創(chuàng)建了一個 FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對象或列表的 512 個引用,而且返回的對象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會 導(dǎo)致沖突待笑。
可用的收回策略有:
LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們莺债。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象滋觉。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。
默認(rèn)的是 LRU齐邦。
flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個合理的毫秒 形式的時間段椎侠。默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔,緩存僅僅調(diào)用語句時刷新。
size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對象數(shù)目和你運行環(huán)境的 可用內(nèi)存資源數(shù)目措拇。默認(rèn)值是 1024我纪。
readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會給所有調(diào)用者返回緩 存對象的相同實例。因此這些對象不能被修改浅悉。這提供了很重要的性能優(yōu)勢趟据。可讀寫的緩存 會返回緩存對象的拷貝(通過序列化) 术健。這會慢一些,但是安全,因此默認(rèn)是 false汹碱。