java之路 myBatis重新學習(二) SQL語句映射XML文件

MyBatis 真正強大之處就在這些映射語句,也就是它的魔力所在。對於它的強大功能,SQL 映射文件的配置卻非常簡單。

如果比較SQL 映射文件配置與JDBC 代碼,很快可以發現,使用SQL 映射文件配置可以節省95%的代碼量。MyBatis 被創建來專注於SQL,但又給我們自己的實現極大的空間。


需要配置的基本元素


1. cache – 配置給定模式的緩存

2. cache-ref – 從別的模式中引用一個緩存

3. resultMap – 這是最複雜而卻強大的一個元素了,它描述如何從結果集中加載對象

4. sql – 一個可以被其他語句複用的SQL 塊

5. insert – 映射INSERT 語句

6. update – 映射UPDATE 語句

7. delete – 映射DELEETE 語句

8. select - 映射SELECT語句



配置注意


SQL 映射XML 文件只有一些基本的元素需要配置,並且要按照下面的順序來定義
寫好SQL語句映射文件後,需要在MyBAtis主配置文件mappers標籤中引用!當然,如果使用spring的話,可以簡化這個配置
例如:

[html] view plaincopy
  1. <!--mappers是告訴MyBatis 去哪尋找映射SQL 的語句。可以使用類路徑中的資源引用,或者使用字符,輸入確切的URL 引用。-->  
  2. <mappers>  
  3.     <mapper resource="com/accp/mybatis/data/BlogMapper.xml" />  
  4. </mappers>  


當Java接口與XML文件在一個相對路徑下時,可以不在myBatis配置文件的mappers中聲明。



SQL 


這個元素可以被用來定義可重用的SQL代碼段,可以包含在其他語句中。

例子請看下面select中例子



SELECT

mybatis select是mybatis 中最常用的元素之一。

對簡單的查詢,select 元素的配置是相當簡單的:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.       
  7.     <!--可重用的SQL代碼段-->  
  8.     <sql id="blog_column">id,title,author_id as authorId</sql>  
  9.       
  10.     <select id="selectBlog_as_map" parameterType="int" resultType="hashmap">  
  11.         select <include refid="blog_column"/> from Blog where id = #{id}  
  12.     </select>  
  13.       
  14. </mapper>  

 這個語句被稱作selectBlog_as_map,使用一個int (或Integer)類型的參數,並返回一個HashMap類型的對象

#{id}告訴mybatis創建了一個PreparedStatement(預處理語句)參數。

在JDBC中,類似的代碼如下:

[java] view plaincopy
  1. String selectBlog_as_map = “select * from Blog where id =?”;   
  2. PreparedStatement ps = conn.prepareStatement(selectBlog_as_map);   
  3. ps.setInt(1,id);   

測試代碼:
[java] view plaincopy
  1. public static void selectBlogAsMap(int id) {  
  2.     SqlSession session = sqlMapper.openSession();  
  3.     Map<String, Object> map = session.selectOne("selectBlog_as_map",id);  
  4.     System.out.println(map);  
  5.     session.close();  
  6. }  


SELECT的屬性還有很多的屬性可以配置,具體的如下:
屬性 描述 取值 默認
id 在這個模式下唯一的標識符,可被其它語句引用    
parameterType 傳給此語句的參數的完整類名或別名    
resultType 語句返回值類型的整類名或別名。注意,如果是集合,
那麼這裏填寫的是集合的項的整類名或別名,而不是集合本身的類名。
(resultType 與resultMap 不能並用)
   
resultMap 引用的外部resultMap 名。結果集映射是MyBatis 中最強大的特性。
許多複雜的映射都可以輕鬆解決。(resultType 與resultMap 不能並用)
   
flushCache 如果設爲true,則會在每次語句調用的時候就會清空緩存。select 語句默認設爲false true|false false
useCache 如果設爲true,則語句的結果集將被緩存。select 語句默認設爲false true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定
true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定 正整數 未設置
fetchSize 設置一個值後,驅動器會在結果集數目達到此數值後,
激發返回,默認爲不設值,由驅動器自己決定
正整數 驅動器決定
statementType statement,preparedstatement,callablestatement。
預準備語句、可調用語句
STATEMENT
PREPARED
CALLABLE
PREPARED
resultSetType forward_only,scroll_sensitive,scroll_insensitive
只轉發,滾動敏感,不區分大小寫的滾動
FORWARD_ONLY
SCROLL_SENSITIVE
SCROLL_INSENSITIVE
驅動器決定




























INSERT

簡單的insert語句:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.   
  7.     <insert id="insertBlog" parameterType="Blog">  
  8.         insert into Blog  
  9.             (id,title,author_id)  
  10.         values  
  11.             (#{id},#{title},#{authorId})  
  12.     </insert>  
  13.   
  14. </mapper>  

對於insert如果你的數據庫支持自動生成主鍵的字段(比如 MySQL 和 SQL Server),那麼你可以設置 useGeneratedKeys=”true”,然後把keyProperty 設成對應的列,就搞定了。

例如Blog表已經對 id 使用了自動生成的列類型,那麼語句如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.   
  7.     <insert id="insertBlog" parameterType="Blog" useGeneratedKeys=”true” keyProperty=”id”>  
  8.         insert into Blog  
  9.             (title,author_id)  
  10.         values  
  11.             (#{title},#{authorId})  
  12.     </insert>  
  13.       
  14. </mapper>  

還可以使用selectKey元素。下面例子,使用mysql數據庫nextval('student')爲自定義函數,用來生成一個key。

例如:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.     <insert id="insertBlog" parameterType="Blog" >  
  7.         <selectKey keyProperty="studentID" resultType="String" order="BEFORE">    
  8.            select nextval('id')    
  9.         </selectKey>    
  10.         insert into Blog  
  11.             (id,title,author_id)  
  12.         values  
  13.             (#{id},#{title},#{authorId})  
  14.     </insert>   
  15. </mapper>  


insert語句屬性配置細節:

屬性 描述 取值 默認
id 在這個模式下唯一的標識符,可被其它語句引用    
parameterType 傳給此語句的參數的完整類名或別名    
flushCache 如果設爲true,則會在每次語句調用的時候就會清空緩存。select 語句默認設爲false true|false false
useCache 如果設爲true,則語句的結果集將被緩存。select 語句默認設爲false true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定
true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定 正整數 未設置
fetchSize 設置一個值後,驅動器會在結果集數目達到此數值後,激發返回,默認爲不設值,由驅動器自己決定 正整數 驅動器決定
statementType statement,preparedstatement,callablestatement。
預準備語句、可調用語句
STATEMENT
PREPARED
CALLABLE
PREPARED
useGeneratedKeys

告訴MyBatis 使用JDBC 的getGeneratedKeys 方法來獲取數據庫自己生成的主鍵(MySQL、SQLSERVER 等

關係型數據庫會有自動生成的字段)。默認:false

true|false false
keyProperty

標識一個將要被MyBatis 設置進getGeneratedKeys 的key 所返回的值,或者爲insert 語句使用一個selectKey

子元素。

   

selectKey語句屬性配置細節:

屬性 描述 取值
keyProperty selectKey 語句生成結果需要設置的屬性。  
resultType 生成結果類型,MyBatis 允許使用基本的數據類型,包括String 、int類型。  
order 可以設成BEFORE 或者AFTER,如果設爲BEFORE,那它會先選擇主鍵,
然後設置keyProperty,再執行insert語句;如果設爲AFTER,它就先運行insert 語句再運行selectKey 語句,
通常是insert 語句中內部調用數據庫(像Oracle)內嵌的序列機制。
BEFORE
AFTER
statementType 像上面的那樣, MyBatis 支持STATEMENT,PREPARED和CALLABLE 的語句形式,
 對應Statement ,PreparedStatement 和CallableStatement 響應
STATEMENT
PREPARED
CALLABLE

UPDATE,DELETE

update 簡單例子:
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.     <update id="updateBlog" parameterType="Blog">    
  7.        UPDATE Blog    
  8.             SET title = #{title},     
  9.                 author_id = #{author.id},    
  10.          WHERE id = #{id};  
  11.     </update>    
  12. </mapper>  

delete 簡單例子:
[html] view plaincopy
  1. <delete id="deleteBlog" parameterType="Blog">    
  2.       DELETE FROM BLOG WHERE ID = #{id}    
  3. </delete>  

update、delete語句屬性配置細節:

屬性 描述 取值 默認
id 在這個模式下唯一的標識符,可被其它語句引用    
parameterType 傳給此語句的參數的完整類名或別名    
flushCache 如果設爲true,則會在每次語句調用的時候就會清空緩存。select 語句默認設爲false true|false false
useCache 如果設爲true,則語句的結果集將被緩存。select 語句默認設爲false true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定
true|false false
timeout 設置驅動器在拋出異常前等待迴應的最長時間,默認爲不設值,由驅動器自己決定 正整數 未設置
fetchSize 設置一個值後,驅動器會在結果集數目達到此數值後,激發返回,默認爲不設值,由驅動器自己決定 正整數 驅動器決定
statementType statement,preparedstatement,callablestatement。
預準備語句、可調用語句
STATEMENT
PREPARED
CALLABLE
PREPARED

Parameters

這個元素說的直白點就是定義參數。注意一個語句中只能有一個參數。
所以參數類型在以後的使用中,可能需要複雜的類型,比如hashmap,一個複雜的對象等。例如:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.       
  7.     <insert id="insertBlog" parameterType="Blog">  
  8.         insert into Blog  
  9.             (id,title,author_id)  
  10.         values  
  11.             (#{id},#{title},#{author.id})  
  12.     </insert>  
  13. </mapper>  


如果blog類型的參數對象傳遞到了語句中,id、title和author屬性將會被查找,然後它們的值就被傳遞到預處理語句的參數中。
這點對於傳遞參數到語句中非常好。但是對於參數映射也有一些其他的特性。
首先,像MyBatis的其他部分,參數可以指定一個確定的數據類型。
[html] view plaincopy
  1. #{property,javaType=int,jdbcType=NUMERIC}  
像MyBatis的剩餘部分,javaType通常可以從參數對象中來確定,除非對象是一個HashMap。那麼javaType應該被確定來保證使用正確類型處理器。
注意:如果null被當作值來傳遞,對於所有可能爲空的列,JDBC Type是需要的。也可以通過閱讀PreparedStatement. setNull()方法的JavaDocs文檔來研究它。
爲了以後自定義類型處理器,你可以指定一個確定的類型處理器類(或別名),比如:
[html] view plaincopy
  1. #{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}  
儘管它看起來繁瑣,但是實際上是你很少設置它們其中之一。
對於數值類型,對於決定有多少數字是相關的,有一個數值範圍。
[html] view plaincopy
  1. #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}  
mode屬性允許你指定IN,OUT或INOUT參數。如果參數爲OUT或INOUT,參數對象屬性的真實值將會被改變,就像你期望你需要你個輸出參數。如果mode爲OUT(或INOUT),而且jdbcType爲CURSOR(也就是Oracle的REFCURSOR),你必須指定一個resultMap來映射結果集到參數類型。要注意這裏的javaType屬性是可選的,如果左邊的空白是jdbcType的CURSOR類型,它會自動地被設置爲結果集。
[html] view plaincopy
  1. #{department,  
  2.     mode=OUT,  
  3.     jdbcType=CURSOR,  
  4.     javaType=ResultSet,  
  5.     resultMap=departmentResultMap}  
字符串替換
默認情況下,使用#{}格式的語法會導致MyBatis創建預處理語句屬性並以它爲背景設置安全的值(比如?)。這樣做很安全,很迅速,也是首選的做法,有時你只是想直接在SQL語句中插入一個不改變的字符串。比如,像ORDER BY,你可以這樣來使用:
ORDER BY ${columnName}
這裏MyBatis不會修改或轉義字符串。

重要:接受從用戶輸出的內容並提供給語句中不變的字符串,這樣做是不安全的。這會導致潛在的SQL注入攻擊,因此你不應該允許用戶輸入這些字段,或者通常自行轉義並檢查。


resultMap

resultMap 元素是MyBatis中最重要最強大的元素。它就是讓你遠離90%的需要從結果集中取出數據的JDBC代碼的那東西,而且在一些情形下允許你做一些JDBC不支持的事情。事實上,編寫相似於對複雜語句聯合映射這些等同的代碼,也許可以跨過上千行的代碼。ResultMap的設計就是簡單語句不需要明確的結果映射,而很多複雜語句確實需要描述它們的關係。

[java] view plaincopy
  1. package com.accp.mybatis.model;  
  2.   
  3. public class Blog {  
  4.     private Integer id;  
  5.     private String title;  
  6.     private Integer authorId;  
  7.   
  8. //省略get和set方法  
  9. }  

基於JavaBean的規範,上面這個類有3個屬性:id,title和authorId。這些在select語句中會精確匹配到列名。
這樣的一個JavaBean可以被映射到結果集,就像映射到HashMap一樣簡單。
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">    
  6.       
  7.     <select id="selectBlog_by_id" parameterType="int" resultType="Blog">  
  8.         select * from Blog where id = #{id}  
  9.     </select>  
  10.   
  11. </mapper>  

這些情況下,MyBatis會在幕後自動創建一個ResultMap,基於屬性名來映射列到JavaBean的屬性上。如果列名沒有精確匹配,你可以在列名上使用select字句的別名(一個標準的SQL特性)來匹配標籤。
ResultMap最優秀的地方你已經瞭解了很多了,但是你還沒有真正的看到一個。只是出於示例的原因,讓我們來看看最後一個示例中外部的resultMap是什麼樣子的,這也是解決列名不匹配的另外一種方式。

[html] view plaincopy
  1. <resultMap id="Blog_result" type="Blog" >  
  2.     <id column="id" property="id" />  
  3.     <result column="title" property="title"/>  
  4.     <result column="author_id" property="authorId"/>  
  5. </resultMap>  



引用它的語句使用resultMap屬性就行了(注意我們去掉了resultType屬性)。比如:
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.accp.mybatis.model.Blog">  
  6.   
  7.   
  8.     <resultMap id="Blog_result" type="Blog" >  
  9.         <id column="id" property="id" />  
  10.         <result column="title" property="title"/>  
  11.         <result column="author_id" property="authorId"/>  
  12.     </resultMap>    
  13.   
  14.     <!-- resultType與resultMap不能同時使用 -->     
  15.     <select id="selectBlog_by_id" parameterType="int" resultMap="Blog_result">  
  16.         select * from Blog where id = #{id}  
  17.     </select>  
  18.   
  19. </mapper>  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章