Mybatis3 (2)xml映射文件
SQL 映射文件有很少的幾個頂級元素(按照它們應該被定義的順序):
- cache – 給定命名空間的緩存配置。
- cache-ref – 其他命名空間緩存配置的引用。
- resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
- parameterMap – 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這里不會記錄。
- sql – 可被其他語句引用的可重用語句塊。
- insert – 映射插入語句
- update – 映射更新語句
- delete – 映射刪除語句
- select – 映射查詢語句
select
查詢
<select id="selectPerson" parameterType="int" resultType="hashmap">SELECT * FROM PERSON WHERE ID = #{id} </select>下面就是 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 setusername = #{username},password = #{password},email = #{email},bio = #{bio}where id = #{id} </update><delete id="deleteAuthor">delete from Author where id = #{id} </delete>在插入語句里面有一些額外的屬性和子元素用來處理主鍵的生成,有多種生成方式。
如果你的數據庫支持自動生成主鍵的字段(比如 MySQL 和 SQL Server),那么你可以設置 useGeneratedKeys=”true”,然后再把 keyProperty 設置到目標屬性上就OK了
<insert id="insertAuthor" useGeneratedKeys="true"keyProperty="id">insert into Author (username,password,email,bio)values (#{username},#{password},#{email},#{bio}) </insert>對不支持自動生成主鍵的JDBC驅動,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>在上面的示例中,selectKey 元素將會首先運行,Author 的 id 會被設置,然后插入語句會被調用。
sql
<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 t1cross join some_table t2 </select>屬性值也可以被用在 include 元素的 refid 屬性里<include refid="${include_target}"/>或include內部語句中${prefix}Table
參數(Parameters)
<insert id="insertUser" parameterType="User">insert into users (id, username, password)values (#{id}, #{username}, #{password}) </insert>如果User類型的參數對象傳遞到了語句中,id、username 和 password 屬性將會被查找。
大多時候你只須簡單地指定屬性名,其他的事情 MyBatis 會自己去推斷,頂多要為可能為空的列指定 jdbcType。
#{firstName} #{middleInitial,jdbcType=VARCHAR} #{lastName}更多選項設置:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Parameters
字符串替換
默認情況,使用 #{} 會導致PreparedStatement參數創建,并安全設置參數。首選!
 有時想插入一個不轉義的字符串,如:
注意:用這種方式不安全,可能導致sql注入,要么不允許用戶輸入這些字段,要么自行轉義驗證。
Result Maps
resultMap 元素是 MyBatis 中最重要最強大的元素。用來支持程序使用 JavaBean 或 POJO(Plain Old Java Objects,普通 Java 對象)作為領域模型。
例如下面配置映射到User實體中
<select id="selectUsers" resultType="com.someapp.model.User">select id, username, hashedPasswordfrom some_tablewhere id = #{id} </select>類型別名可以幫助你不用輸入類的完全限定名
<!-- In mybatis-config.xml file --> <typeAlias type="com.someapp.model.User" alias="User"/><!-- In SQL Mapping XML file --> <select id="selectUsers" resultType="User">select id, username, hashedPasswordfrom some_tablewhere id = #{id} </select>Mybatis會創建一個ResultMap,映射到javaBean中。如果沒有匹配上,可以再select語句中使用別名
<select id="selectUsers" resultType="User">selectuser_id as "id",user_name as "userName",hashed_password as "hashedPassword"from some_tablewhere id = #{id} </select>下面是另一種方式來實現映射。
<resultMap id="userResultMap" type="User"><id property="id" column="user_id" /><result property="username" column="user_name"/><result property="password" column="hashed_password"/> </resultMap>引用它的語句時使用resultMap屬性(我們去掉了resultType屬性)。
<select id="selectUsers" resultMap="userResultMap">select user_id, user_name, hashed_passwordfrom some_tablewhere id = #{id} </select>總結:resultMap可以用來解決數據庫列名與屬性沒有匹配的問題。如果足夠了解它,就不需要顯示配置它。
高級結果映射
<!-- 超復雜的 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>解析:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps
構造方法
public class User {//...public User(Integer id, String username, int age) {//...} //... }將結果注入構造方法,Mybatis需要通過某種方式定位相應構造方法。constructor 元素就是為此而生的。
<constructor><idArg column="id" javaType="int"/><arg column="username" javaType="String"/><arg column="age" javaType="_int"/> </constructor>從版本 3.4.3 開始,可以在指定參數名稱的前提下,以任意順序編寫 arg 元素。可以添加@Param注解做到
<constructor><idArg column="id" javaType="int" name="id" /> <!--name是javaBean中屬性,column是數據庫中字段--><arg column="age" javaType="_int" name="age" /><arg column="username" javaType="String" name="username" /> </constructor>如果類中存在名稱和類型相同的屬性,那么可以省略 javaType 。
關聯
<association property="author" column="blog_author_id" javaType="Author"><id property="id" column="author_id"/><result property="username" column="author_username"/> </association>關聯的嵌套查詢
<resultMap id="blogResult" type="Blog"><association property="author" column="author_id" javaType="Author" select="selectAuthor"/> </resultMap><select id="selectBlog" resultMap="blogResult">SELECT * FROM BLOG WHERE ID = #{id} </select><select id="selectAuthor" resultType="Author">SELECT * FROM AUTHOR WHERE ID = #{id} </select>我們有兩個查詢語句:一個來加載博客,另外一個來加載作者,而且博客的結果映射描 述了“selectAuthor”語句應該被用來加載它的 author 屬性。
 其他所有的屬性將會被自動加載,假設它們的列和屬性名相匹配。
這種方式很簡單,但是對于大型數據集合和列表表現不好,原因是我們熟悉的“N+1 查詢問題”
- 你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。
- 對返回的每條記錄,你執行了一個查詢語句來為每個加載細節(就是“N”)。
Mybatis能延時加載是好事,但是加載完后立即調用所有延遲加載,就很糟糕。
有另外一種方法。
關聯的嵌套結果
<select id="selectBlog" resultMap="blogResult">selectB.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_biofrom Blog B left outer join Author A on B.author_id = A.idwhere B.id = #{id} </select>注意這個聯合查詢, 使用唯一而且清晰的名字來重命名。 使映射非常簡單。
<resultMap id="blogResult" type="Blog"><id property="id" column="blog_id" /><result property="title" column="blog_title"/><association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/> </resultMap><resultMap id="authorResult" type="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"/> </resultMap>在上面,authorResult 用來加載作者實例。現在,上面的示例用了外部的結果映射元素來映射關聯。這使得 Author 結果映射可以 重用
非常重要: id元素在嵌套結果映射中扮演著非 常重要的角色。 不指定唯一標志屬性,會有嚴重的性能問題。
如果不需要映射到單獨的結果映射中,也可以嵌套結果映射。
<resultMap id="blogResult" type="Blog"><id property="id" column="blog_id" /><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"/></association> </resultMap>集合
<collection property="posts" ofType="domain.blog.Post"><id property="id" column="post_id"/><result property="subject" column="post_subject"/><result property="body" column="post_body"/> </collection>和關聯相同,不同處:
private List<Post> posts;集合的嵌套查詢
首先,讓我們看看使用嵌套查詢來為博客加載文章。
<resultMap id="blogResult" type="Blog"><collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/> </resultMap><select id="selectBlog" resultMap="blogResult">SELECT * FROM BLOG WHERE ID = #{id} </select><select id="selectPostsForBlog" resultType="Post">SELECT * FROM POST WHERE BLOG_ID = #{id} </select>關注這段
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>讀作:“在Post類型的ArrayList中的posts的集合”。
集合的嵌套結果
至此,你可以猜測集合的嵌套結果是如何來工作的,因為它和關聯完全相同,除了它應 用了一個“ofType”屬性
 詳細介紹:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps
 你的應用在找到最佳方法前要一直進行的單元測試和性 能測試。
鑒別器
<discriminator javaType="int" column="draft"><case value="1" resultType="DraftPost"/></discriminator>有時一個單獨的數據庫查詢也許返回很多不同 (但是希望有些關聯) 數據類型的結果集。 鑒別器元素就是被設計來處理這個情況的, 還有包括類的繼承層次結構。和switch語句類似。
自動映射
如果數據庫字段名和javaBean屬性名不一致,要將 mapUnderscoreToCamelCase設置為true。
例如:
<select id="selectUsers" resultMap="userResultMap">selectuser_id as "id",user_name as "userName",hashed_passwordfrom some_tablewhere id = #{id} </select> <resultMap id="userResultMap" type="User"><result property="password" column="hashed_password"/> </resultMap>上面的例子中,id和userName和javaBean中屬性一致,被自動映射了。而hashed_password在resultMap中映射了字段和屬性,所以在結果中也能取到值。
有三種自動映射等級:
- NONE - 禁用自動映射。僅設置手動映射屬性。
- PARTIAL(默認) - 將自動映射結果除了那些有內部定義內嵌結果映射的(joins).
- FULL - 自動映射所有。
緩存
一級緩存是SQLSession級別的緩存,換出的數據只在SQLSession內有效。
 二級緩存是mapper級別的緩存,同一個namespace公用這個緩存,所以對SQLSession是共享的
一級緩存
1.第一次執行select完畢會將查到的數據寫入SqlSession內的HashMap中緩存起來
2.第二次執行select會從緩存中查數據,如果select相同切傳參數一樣,那么就能從緩存中返回數據,不用去數據庫了,從而提高了效率
注意事項:
- 如果SqlSession執行了DML操作(insert、update、delete),并commit了,那么mybatis就會清空當前SqlSession緩存中的所有緩存數據,這樣可以保證緩存中的存的數據永遠和數據庫中一致,避免出現臟讀
- 當一個SqlSession結束后那么他里面的一級緩存也就不存在了,mybatis默認是開啟一級緩存,不需要配置
- mybatis的緩存是基于[namespace:sql語句:參數]來進行緩存的,意思就是,SqlSession的HashMap存儲緩存數據時,是使用[namespace:sql:參數]作為key,查詢返回的語句作為value保存的。例如:-1242243203:1146242777:winclpt.bean.userMapper.getUser:0:2147483647:select * from user where id=?:19
二級緩存
二級緩存是mapper級別的緩存。也就是同一個namespace的mapper.xml,當多個SQLSession使用同一個mapper操作數據庫,得到的數據會緩存在同一個二級緩存中。
具體流程:
   1.當一個sqlseesion執行了一次select后,在關閉此session的時候,會將查詢結果緩存到二級緩存
   2.當另一個sqlsession執行select時,首先會在他自己的一級緩存中找,如果沒找到,就回去二級緩存中找,找到了就返回,就不用去數據庫了,從而減少了數據庫壓力提高了性能
注意事項:
    如果SqlSession執行了DML操作(insert、update、delete),并commit了,那么mybatis就會清空當前mapper緩存中的所有緩存數據,這樣可以保證緩存中的存的數據永遠和數據庫中一致,避免出現臟讀。
開啟二級緩存:
 confg.xml
userMapper.xml
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/> 當前mapper下所有語句開啟二級緩存配置了一個LRU緩存,并每隔60秒刷新,最大存儲512個對象,返回的對象是只讀。
 若想禁用某select語句的二級緩存,添加userCache="false"。
可用的收回策略有:
 LRU – 最近最少使用的:移除最長時間不被使用的對象。
 FIFO – 先進先出:按對象進入緩存的順序來移除它們。
 SOFT – 軟引用:移除基于垃圾回收器狀態和軟引用規則的對象。
 WEAK – 弱引用:更積極地移除基于垃圾收集器狀態和弱引用規則的對象。
使用自定義緩存
總結
以上是生活随笔為你收集整理的Mybatis3 (2)xml映射文件的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Sprng boot(十三):Sprin
- 下一篇: lol符文灵性猎手的效果(lol天赋灵性
