MyBatis框架淺析之 Mapper.xml 映射文件
Mapper XML 文件
MyBatis 的真正強大在於它的映射語句,也是它的魔力所在。由於它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發現省掉了將近 95% 的代碼。MyBatis 就是針對 SQL 構建的,並且比普通的方法做的更好。
同樣需要介紹定級元素:
mapper
- cache – 給定命名空間的緩存配置。
- cache-ref – 其他命名空間緩存配置的引用。
- resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
parameterMap– 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這裏不會記錄。- sql – 可被其他語句引用的可重用語句塊。
- insert – 映射插入語句
- update – 映射更新語句
- delete – 映射刪除語句
- select – 映射查詢語句
1.mapper 根節點
有且必須只有一個屬性值:namespace, 建議設置為Mapper接口的全限定名
<mapper namespace="com.baoxian.dao.UserInfoMapper"> ... </mapper>
2.select 元素
2.1 簡單的select語句
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id} </select>
解釋一下上面配置:
這個語句被稱作 selectPerson,接受一個 int(或 Integer)類型的參數,並返回一個 HashMap 類型的對象,其中的鍵是列名,值便是結果行中的對應值。
假如調用該條SQL傳入的 參數為 1,selectPerson(1)
原來的sql語句經過處理後相當於 SELECT * FROM PERSON WHERE ID = ?
?相當於參數的占位符
調用時傳入的 參數值 將會被替換
2.2 select元素中的所有屬性
<select id="selectPerson" #必須 parameterType="int" #可選,寫出來會更加直觀 parameterMap="deprecated" #已不使用 resultType="hashmap" #必須指定 resultMap="personResultMap"#自定義結果集的映射 flushCache="false" #調用該語句是否刷新緩存,一般insert update delete 會配置成true useCache="true" # timeout="10000" # 語句最大等待時間 10S fetchSize="256" # statementType="PREPARED" resultSetType="FORWARD_ONLY">
屬性 | 描述 |
---|---|
id | 在命名空間中唯一的標識符,可以被用來引用這條語句。 |
parameterType | 將會傳入這條語句的參數類的完全限定名或別名。這個屬性是可選的,因為 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數,默認值為 unset。 |
resultType | 從這條語句中返回的期望類型的類的完全限定名或別名。註意如果是集合情形,那應該是集合可以包含的類型,而不能是集合本身。使用 resultType 或 resultMap,但不能同時使用。 |
resultMap | 外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多復雜映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同時使用。 |
flushCache | 將其設置為 true,任何時候只要語句被調用,都會導致本地緩存和二級緩存都會被清空,默認值:false。 |
useCache | 將其設置為 true,將會導致本條語句的結果被二級緩存,默認值:對 select 元素為 true。 |
timeout | 這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值為 unset(依賴驅動)。 |
fetchSize | 這是嘗試影響驅動程序每次批量返回的結果行數和這個設置值相等。默認值為 unset(依賴驅動)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個,默認值為 unset (依賴驅動)。 |
databaseId | 如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 |
resultOrdered | 這個設置僅針對嵌套結果 select 語句適用:如果為 true,就是假設包含了嵌套結果集或是分組了,這樣的話當返回一個主結果行的時候,就不會發生有對前面結果集的引用的情況。這就使得在獲取嵌套的結果集的時候不至於導致內存不夠用。默認值:false。 |
resultSets | 這個設置僅對多結果集的情況適用,它將列出語句執行後返回的結果集並每個結果集給一個名稱,名稱是逗號分隔的。 |
2.3 insert ,update,delete
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" #將JDBC生成的主鍵值 賦值給keyProperty對應的屬性名 keyColumn="" useGeneratedKeys="" #取出JDBC生成的主鍵 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 | 命名空間中的唯一標識符,可被用來代表這條語句。 |
parameterType | 將要傳入語句的參數的完全限定類名或別名。這個屬性是可選的,因為 MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數,默認值為 unset。 |
flushCache | 將其設置為 true,任何時候只要語句被調用,都會導致本地緩存和二級緩存都會被清空,默認值:true(對應插入、更新和刪除語句)。 |
timeout | 這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值為 unset(依賴驅動)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
useGeneratedKeys | (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關系數據庫管理系統的自動遞增字段),默認值:false。 |
keyProperty | (僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設置它的鍵值,默認:unset。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
keyColumn | (僅對 insert 和 update 有用)通過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候需要設置。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
databaseId | 如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當前 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>
如果設置了主鍵自增,則上述insert語句可以更改為:
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
如果數據庫支持多行插入(例如MySQL數據庫),則insert語句可以修改為:
<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>
其中foreach 會對集合進行叠代 , item 表示集合中每個元素,collection 表示集合的類型, separator表示分隔符,並且智能的在最後一個元素後去除分隔符
如果數據庫不支持自動生成主鍵,則可以使用另外一種 MyBatis提供的方式
<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>
上述語句的執行順序是,先執行自動生成隨機ID的語句, 並將隨機生成的值轉成int類型 再通過set方法 設置到Author的id屬性中,從而執行插入時,id屬性值將對應數據庫的id列,插入到數據庫中
selectKey 的重要屬性如下:
<selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED">
屬性 | 描述 |
---|---|
keyProperty | selectKey 語句結果應該被設置的目標屬性。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
keyColumn | 匹配屬性的返回結果集中的列名稱。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
resultType | 結果的類型。MyBatis 通常可以推算出來,但是為了更加確定寫上也不會有什麽問題。MyBatis 允許任何簡單類型用作主鍵的類型,包括字符串。如果希望作用於多個生成的列,則可以使用一個包含期望屬性的 Object 或一個 Map。 |
order | 這可以被設置為 BEFORE 或 AFTER。如果設置為 BEFORE,那麽它會首先選擇主鍵,設置 keyProperty 然後執行插入語句。如果設置為 AFTER,那麽先執行插入語句,然後是 selectKey 元素 - 這和像 Oracle 的數據庫相似,在插入語句內部可能有嵌入索引調用。 |
statementType | 與前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 語句的映射類型,分別代表 PreparedStatement 和 CallableStatement 類型。 |
2.4 sql
sql元素可以用來定義可復用的sql代碼:
<sql id="fromClause"> /*通過${}取調用者傳遞的屬性值*/ from ${tableName} </sql>
使用<include>元素調用定義的sql元素,以下是簡單的實現了復用的效果,往往實際中會更加復雜:
<!--通過ID查找用戶--> <select id="selectUserById" resultMap="BaseResultMap" parameterType="java.lang.Long" > select id,userName,age /*通過property屬性 向sql元素動態傳遞參數值,兩邊規定好property的屬性名稱即可*/ <include refid="fromClause"> <property name="tableName" value="userinfo"/> </include> where id = #{id} </select> <!--查詢出所有用戶--> <select id="selectAll" resultMap="BaseResultMap" > select id, username,age <include refid="fromClause"> <property name="tableName" value="userinfo"/> </include> </select>
此外,調用者傳遞過的屬性值,同樣也可以使用在include 元素的 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>
2.5 參數 parameters
sql語句接收的參數有兩種類型,一種是基本類型,另一種是復雜的對象類型
如果sql語句 接收的參數是一個對象.那麽傳遞過來的對象要提供相應的getter方法,此時mybatis才能正確的取出屬性值
例如:
<!--通過ID更新用戶--> <update id="updateByPrimaryKey" parameterType="com.baoxian.domain.UserInfo" > update UserInfo set username = #{userName},age = #{age} where id = #{id} </update>
每一個參數都支持為其指定特殊的類型
格式如下:
<!--通過ID更新用戶--> <update id="updateByPrimaryKey" parameterType="com.baoxian.domain.UserInfo" > update UserInfo set username = #{userName},age = #{age,javaType=int,jdbcType=NUMERIC} where id = #{id} </update>
其中age參數,指明java類型是int , jdbcType是NUMERIC
如果傳遞一個為null的參數值到數據庫中,並且該列允許為null,那麽必須為該參數指定javaType
除了javaType,與 jdbcType之外,還可以指定以下:
typeHandler: 需要特殊類型處理器處理參數的映射 (幾乎不用這麽做)
numericScale:如果參數值是一個小數,希望保存進數據庫的值 保留小數點後兩位 ,則可以通這樣實現: #{salary,javaType=double,jdbcType=NUMERIC,numericScale=2}
mode:該屬性有三個可選值,IN,OUT,及INOUT;如果參數為 OUT 或 INOUT,參數對象屬性的真實值將會被改變,就像你在獲取輸出參數時所期望的那樣。
如果 mode 為 OUT(或 INOUT),而且 jdbcType 為 CURSOR(也就是 Oracle 的 REFCURSOR),你必須指定一個 resultMap 來映射結果集 ResultMap 到參數類型。
要註意這裏的 javaType 屬性是可選的,如果留空並且 jdbcType 是 CURSOR,它會被自動地被設為 ResultMap。
說了那麽多,其實更多時候,我們90%的情況是不需要為參數指定什麽額外屬性,MyBatis已經幫你做好該做的
最多在java參數為null時,指定javaType即可
2.6 字符串替換
使用#{} 會生成一個預處理參數,提高了SQL的安全性, 但有時不希望對參數值進行轉義,保持參數原本的值,則可以使用 ${}進行取值
MyBatis框架淺析之 Mapper.xml 映射文件