mybatis配置mapper.xml 的基本操做

XML 映射文件

  本文參考mybatis中文官網進行學習總結:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.htmlhtml

  MyBatis 的真正強大在於它的映射語句,這是它的魔力所在。因爲它的異常強大,映射器的 XML 文件就顯得相對簡單。若是拿它跟具備相同功能的 JDBC 代碼進行對比,你會當即發現省掉了將近 95% 的代碼。MyBatis 爲聚焦於 SQL 而構建,以儘量地爲你減小麻煩。java

  SQL 映射文件只有不多的幾個頂級元素(按照應被定義的順序列出):sql

  • cache – 對給定命名空間的緩存配置。
  • cache-ref – 對其餘命名空間緩存配置的引用。
  • resultMap – 是最複雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
  • sql – 可被其餘語句引用的可重用語句塊。
  • insert – 映射插入語句
  • update – 映射更新語句
  • delete – 映射刪除語句
  • select – 映射查詢語句

select

  查詢語句是 MyBatis 中最經常使用的元素之一,光能把數據存到數據庫中價值並不大,只有還能從新取出來纔有用,多數應用也都是查詢比修改要頻繁。對每一個插入、更新或刪除操做,一般間隔多個查詢操做。這是 MyBatis 的基本原則之一,也是將焦點和努力放在查詢和結果映射的緣由。簡單查詢的 select 元素是很是簡單的。好比:數據庫

<resultMap id="BaseResultMap" type="blog">
     <id column="bid" property="bid" jdbcType="INTEGER"/>
     <result column="name" property="name" jdbcType="VARCHAR"/>
     <result column="author_id" property="authorId" jdbcType="INTEGER"/>
</resultMap>
<!--****************************************************************************************-->
<!--簡單查詢-->
<select id="selectBlogById" resultMap="BaseResultMap" statementType="PREPARED" useCache="false">
     select * from blog where bid = #{bid}
</select>

  #{bid} 這就告訴 MyBatis 建立一個預處理語句(PreparedStatement)參數,在 JDBC 中,這樣的一個參數在 SQL 中會由一個「?」來標識,並被傳遞到一個新的預處理語句中,就像這樣:數組

// 近似的 JDBC 代碼,非 MyBatis 代碼...
String selectBlogById= "SELECT * FROM BLOG WHERE BID=?";
PreparedStatement ps = conn.prepareStatement(selectBlogById);
ps.setInt(1,bid);

  固然,使用 JDBC 意味着須要更多的代碼來提取結果並將它們映射到對象實例中,而這就是 MyBatis 節省你時間的地方。select 元素容許你配置不少屬性來配置每條語句的做用細節。緩存

<select
  id="selectPerson"
  parameterType="int"
  parameterMap="deprecated"
  resultType="hashmap"
  resultMap="personResultMap"
  flushCache="false"
  useCache="true"
  timeout="10"
  fetchSize="256"
  statementType="PREPARED"
  resultSetType="FORWARD_ONLY">

   相關屬性描述:mybatis

屬性 描述
id 在命名空間中惟一的標識符,能夠被用來引用這條語句。
parameterType 將會傳入這條語句的參數類的徹底限定名或別名。這個屬性是可選的,由於 MyBatis 能夠經過類型處理器(TypeHandler) 推斷出具體傳入語句的參數,默認值爲未設置(unset)。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。請使用內聯參數映射和 parameterType 屬性。
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 或 DEFAULT(等價於 unset) 中的一個,默認值爲 unset (依賴驅動)。
databaseId 若是配置了數據庫廠商標識(databaseIdProvider),MyBatis 會加載全部的不帶 databaseId 或匹配當前 databaseId 的語句;若是帶或者不帶的語句都有,則不帶的會被忽略。
resultOrdered 這個設置僅針對嵌套結果 select 語句適用:若是爲 true,就是假設包含了嵌套結果集或是分組,這樣的話當返回一個主結果行的時候,就不會發生有對前面結果集的引用的狀況。 這就使得在獲取嵌套的結果集的時候不至於致使內存不夠用。默認值:false
resultSets 這個設置僅對多結果集的狀況適用。它將列出語句執行後返回的結果集並給每一個結果集一個名稱,名稱是逗號分隔的。

 insert, update 和 delete:

  數據變動語句 insert,update 和 delete 的實現很是接近:框架

<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">

   相關屬性描述:dom

屬性 描述
id 命名空間中的惟一標識符,可被用來表明這條語句。
parameterType 將要傳入語句的參數的徹底限定類名或別名。這個屬性是可選的,由於 MyBatis 能夠經過類型處理器推斷出具體傳入語句的參數,默認值爲未設置(unset)。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。請使用內聯參數映射和 parameterType 屬性。
flushCache 將其設置爲 true 後,只要語句被調用,都會致使本地緩存和二級緩存被清空,默認值:true(對於 insert、update 和 delete 語句)。
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 語句的示例:ide

<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>

  如前所述,插入語句的配置規則更加豐富,在插入語句裏面有一些額外的屬性和子元素用來處理主鍵的生成,並且有多種生成方式。首先,若是你的數據庫支持自動生成主鍵的字段(好比 MySQL 和 SQL Server),那麼你能夠設置 useGeneratedKeys=」true」,而後再把 keyProperty 設置到目標屬性上就 OK 了。若是你的數據庫還支持多行插入, 你也能夠傳入一個 Blog數組或集合,並返回自動生成的主鍵。

<!--批量插入-->
<insert id="insertBlogs" useGeneratedKeys="true"
            keyProperty="bid">
     insert into blog (name, author_id) values
     <foreach item="item" collection="list" separator=",">
         (#{item.name}, #{item.authorId})
     </foreach>
</insert>

sql

  這個元素能夠被用來定義可重用的 SQL 代碼段,這些 SQL 代碼能夠被包含在其餘語句中。它能夠(在加載的時候)被靜態地設置參數。 在不一樣的包含語句中能夠設置不一樣的值到參數佔位符上。mybatis中sql標籤與include標籤進行配合,靈活的查詢須要的數據。

<sql id="ref">
    bid,name,authorId
</sql>

<select id="selectbyId" resultMap="BaseResultMap">
    select
    <include refid="ref"/>
    from
    blog where bid = #{bid}
</select>

  sql標籤中id屬性對應include標籤中的refid屬性。經過include標籤將sql片斷和原sql片斷進行拼接成一個完成的sql語句進行執行。include標籤中還能夠用property標籤,用以指定自定義屬性。

<select id="selectbyId" resultMap="BaseResultMap">
    select
    <include refid="ref">
        <property name="abc" value="bid"/>
    </include>
    from
    blog where bid = #{bid}
</select>

  此時,能夠在sql標籤中取出對應設置的自定義屬性中的值,例如接上代碼例子:

<sql id="ref">
    ${abc},name,authorId
</sql>

<select id="selectbyId" resultMap="BaseResultMap">
    select
    <include refid="ref">
        <property name="abc" value="bid"/>
    </include>
    from
    blog where bid = #{bid}
</select>

   在sql標籤中經過${}取出對應include標籤中設置的屬性值。

  關聯(association)元素處理「有一個」類型的關係。 好比,在咱們的示例中,一個博客有一個用戶。關聯結果映射和其它類型的映射工做方式差很少。 你須要指定目標屬性名以及屬性的javaType(不少時候 MyBatis 能夠本身推斷出來),在必要的狀況下你還能夠設置 JDBC 類型,若是你想覆蓋獲取結果值的過程,還能夠設置類型處理器。關聯的不一樣之處是,你須要告訴 MyBatis 如何加載關聯。MyBatis 有兩種不一樣的方式加載關聯:

  • 嵌套 Select 查詢:經過執行另一個 SQL 映射語句來加載指望的複雜類型。
  • 嵌套結果映射:使用嵌套的結果映射來處理鏈接結果的重複子集。

關聯的嵌套 Select 查詢

<!-- 另外一種聯合查詢(一對一)的實現,可是這種方式有「N+1」的問題 -->
    <resultMap id="BlogWithAuthorQueryMap" type="com.wuzz.demo.associate.BlogAndAuthor">
        <id column="bid" property="bid" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <association property="author" javaType="com.wuzz.demo.entity.Author"
                     column="author_id" select="selectAuthor"/>
    </resultMap>

    <!-- 嵌套查詢 -->
    <select id="selectAuthor" parameterType="int" resultType="com.wuzz.demo.entity.Author">
        select author_id authorId, author_name authorName
        from author where author_id = #{authorId}
    </select>

    <!-- 根據文章查詢做者,一對一,嵌套查詢,存在N+1問題,可經過開啓延遲加載解決 -->
    <select id="selectBlogWithAuthorQuery" resultMap="BlogWithAuthorQueryMap" >
        select b.bid, b.name, b.author_id, a.author_id , a.author_name
        from blog b
        left join author a
        on b.author_id=a.author_id
        where b.bid = #{bid, jdbcType=INTEGER}
    </select>

  就是這麼簡單。咱們有兩個 select 查詢語句:一個用來加載博客(Blog),另一個用來加載做者(Author),並且博客的結果映射描述了應該使用 selectAuthor 語句加載它的 author 屬性。其它全部的屬性將會被自動加載,只要它們的列名和屬性名相匹配。這種方式雖然很簡單,但在大型數據集或大型數據表上表現不佳。這個問題被稱爲「N+1 查詢問題」。 歸納地講,N+1 查詢問題是這樣子的:

  • 你執行了一個單獨的 SQL 語句來獲取結果的一個列表(就是「+1」)。
  • 對列表返回的每條記錄,你執行一個 select 查詢語句來爲每條記錄加載詳細信息(就是「N」)。

  這個問題會致使成百上千的 SQL 語句被執行。有時候,咱們不但願產生這樣的後果。MyBatis 可以對這樣的查詢進行延遲加載,所以能夠將大量語句同時運行的開銷分散開來。mybatis.configuration.lazy-loading-enabled=true 能夠開啓延時加載 mybatis.configuration.aggressive-lazy-loading=true 能夠指定哪些方法調用查詢, 然而,若是你加載記錄列表以後馬上就遍歷列表以獲取嵌套的數據,就會觸發全部的延遲加載查詢,性能可能會變得很糟糕。因此還有另一種方法。

關聯的嵌套結果映射

<!-- 根據文章查詢做者,一對一查詢的結果,嵌套查詢 -->
    <resultMap id="BlogWithAuthorResultMap" type="com.wuzz.demo.associate.BlogAndAuthor">
        <id column="bid" property="bid" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <!-- 聯合查詢,將author的屬性映射到ResultMap -->
        <association property="author" javaType="com.wuzz.demo.entity.Author">
            <id column="author_id" property="authorId"/>
            <result column="author_name" property="authorName"/>
        </association>
    </resultMap>
    <!-- 根據文章查詢做者,一對一,嵌套結果,無N+1問題 -->
    <select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap" >
        select b.bid, b.name, b.author_id, a.author_id , a.author_name
        from blog b,author a
        where b.author_id=a.author_id and b.bid = #{bid, jdbcType=INTEGER}
    </select>

   查詢文章帶評論的結果(一對多)映射:

<!--  查詢文章帶評論的結果(一對多) -->
    <resultMap id="BlogWithCommentMap" type="com.wuzz.demo.associate.BlogAndComment" extends="BaseResultMap" >
        <collection property="comment" ofType="com.wuzz.demo.entity.Comment">
            <id column="comment_id" property="commentId" />
            <result column="content" property="content" />
            <result column="bid" property="bid" />
        </collection>
    </resultMap>
    <!-- 根據文章查詢評論,一對多 -->
    <select id="selectBlogWithCommentById" resultMap="BlogWithCommentMap" >
        select b.bid, b.name, b.author_id , c.comment_id , c.content,c.bid
        from blog b, comment c
        where b.bid = c.bid
        and b.bid = #{bid}
    </select>

  按做者查詢文章評論的結果(多對多):

<!--  按做者查詢文章評論的結果(多對多) -->
    <resultMap id="AuthorWithBlogMap" type="com.wuzz.demo.associate.AuthorAndBlog" >
        <id column="author_id" property="authorId" jdbcType="INTEGER"/>
        <result column="author_name" property="authorName" jdbcType="VARCHAR"/>
        <collection property="blog" ofType="com.wuzz.demo.associate.BlogAndComment">
            <id column="bid" property="bid" />
            <result column="name" property="name" />
            <result column="author_id" property="authorId" />
            <collection property="comment" ofType="com.wuzz.demo.entity.Comment">
                <id column="comment_id" property="commentId" />
                <result column="content" property="content" />
                <result column="bid" property="bid" />
            </collection>
        </collection>
    </resultMap>

    <!-- 根據做者文章評論,多對多 -->
    <select id="selectAuthorWithBlog" resultMap="AuthorWithBlogMap" >
        select b.bid, b.name, a.author_id , a.author_name , c.comment_id , c.content,c.bid
        from blog b, author a, comment c
        where b.author_id = a.author_id and b.bid = c.bid
    </select>

動態 SQL

  MyBatis 的強大特性之一即是它的動態 SQL。若是你有使用 JDBC 或其它相似框架的經驗,你就能體會到根據不一樣條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性能夠完全擺脫這種痛苦。雖然在之前使用動態 SQL 並不是一件易事,但正是 MyBatis 提供了能夠被用在任意 SQL 映射語句中的強大的動態 SQL 語言得以改進這種情形。動態 SQL 元素和 JSTL 或基於相似 XML 的文本處理器類似。在 MyBatis 以前的版本中,有不少元素須要花時間瞭解。MyBatis 3 大大精簡了元素種類,如今只需學習原來一半的元素即可。MyBatis 採用功能強大的基於 OGNL 的表達式來淘汰其它大部分元素。

  1. if
  2. choose (when, otherwise)
  3. trim (where, set)
  4. foreach

  其中  choose再實際開發中應用的較少,咱們這裏就其餘3個標籤進行測試

<!--動態sql-->
    <select id="selectBlogById2" resultMap="BaseResultMap" statementType="PREPARED" useCache="false"
        parameterType="blog">
        select * from blog
        <trim prefix="WHERE" prefixOverrides="AND |OR ">
            <if test="bid != null and bid !='' ">
                bid = #{bid}
            </if>
            <if test="name != null and name !='' ">
                AND name = #{name}
            </if>
            <if test="authorId != null and authorId != ''">
                AND author_id = #{author_id}
            </if>
        </trim>
    </select>

   foreach:動態 SQL 的另一個經常使用的操做需求是對一個集合進行遍歷,一般是在構建 IN 條件語句的時候。好比:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>
相關文章
相關標籤/搜索