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