MyBatisの動的SQL

53365 ワード

MyBatisの強力な特性の一つは、そのダイナミックSQLです.JDBCなどのフレームワークを使った経験があれば、条件によってSQL文をつづるのがどんなに苦しいかを味わうことができます.つなぎ合わせるときは、必要なスペースを忘れないようにし、列名リストの最後のカンマを省くことに注意してください.ダイナミックSQLという特性を利用して、このような苦痛から完全に抜け出すことができます.
通常、動的SQLを使用するのは独立した一部ではありません.MyBatisはもちろん、任意のSQLマッピング文で使用できる強力な動的SQL言語を使用してこの状況を改善します.
動的SQL要素は、JSTLまたはXMLベースの他のテキストプロセッサと似ています.MyBatisの以前のバージョンでは、多くの要素を理解する必要があります.MyBatis 3はそれらを大幅に向上させ、今では元の半分の要素を使うことができません.MyBatisは強力なOGLNLベースの式を採用し、他の要素を除去しています.
  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

  • ifダイナミックSQLでは、where句の一部を条件付きで含めることが一般的です.例:
    <select id="findActiveBlogWithTitleLike"
        resultType="Blog">

     SELECT * FROM BLOG
     WHERE state = ‘ACTIVE’
     <if test="title != null">
       AND title like #{title}
     if>
    select>

    この文は、オプションのテキスト検索タイプの機能を提供します.「title」が伝わらなければ、「ACTIVE」状態のBLOGはすべて返される.逆に「title」が入力されると、「title」の内容を曖昧に検索したBLOG結果が返されます(この例では、注意深い読者は、パラメータ値がマスクやワイルドカードを含むことができることを発見します).
    オプションで「title」と「author」の2つの条件で検索したい場合はどうすればいいですか?まず、文の名前を変えてより現実的な意味を持つようにします.そしてもう一つの条件を加えればいい.
    <select id="findActiveBlogLike"
        resultType="Blog">

     SELECT * FROM BLOG WHERE state = ‘ACTIVE’
     <if test="title != null">
       AND title like #{title}
     if>
     <if test="author != null and author.name != null">
       AND author_name like #{author.name}
     if>
    select>

    choose,when,otherwiseある時、私たちはすべての条件文を使いたくなくて、その中から1、2を選びたいだけです.この場合、MyBatisはJavaのswitch文に似たchoose要素を提供します.
    やはり上記の例ですが、今回は「title」を提供して「title」を押して検索し、「author」を提供して「author」を押して検索し、両方が提供されていない場合は、すべての条件に合致するBLOGを返します(実際には、管理者が一定のポリシーでBLOGリストを選択し、多くの無意味なランダムな結果を返すのではなく、一定のポリシーでBLOGリストを選択する可能性があります).
    <select id="findActiveBlogLike"
        resultType="Blog">

     SELECT * FROM BLOG WHERE state = ‘ACTIVE’
     <choose>
       <when test="title != null">
         AND title like #{title}
       when>
       <when test="author != null and author.name != null">
         AND author_name like #{author.name}
       when>
       <otherwise>
         AND featured = 1
       otherwise>
     choose>
    select>

    trim,where,setの前のいくつかの例はすでに悪名高い動的SQL問題を適切に解決した.ここで「if」の例に戻ることを考えて、今回は「ACTIVE=1」も動的な条件に設定して、何が起こるか見てみましょう.
    <select id="findActiveBlogLike"
        resultType="Blog">

     SELECT * FROM BLOG
     WHERE
     <if test="state != null">
       state = #{state}
     if>
     <if test="title != null">
       AND title like #{title}
     if>
     <if test="author != null and author.name != null">
       AND author_name like #{author.name}
     if>
    select>

    もしこれらの条件が一致しなかったらどうなりますか?最終的にこのSQLはこのようになります:SELECT*FROM BLOG WHEREこれはクエリの失敗を招きます.2番目の条件だけが一致したらどうなりますか?このSQLは最終的には、SELECT*FROM BLOG WHERE AND title like「someTitle」というクエリも失敗します.この問題は簡単に条件文式で解決することはできません.もしあなたもこのように書かなければならなかったら、あなたはこれからこのように書きたくないかもしれません.
    MyBatisには簡単な処理があり、90%の場合に役立ちます.使用できない場所では、処理方法をカスタマイズして正常に動作させることができます.簡単な修正で目的の効果が得られます.
    <select id="findActiveBlogLike"
        resultType="Blog">

     SELECT * FROM BLOG
     <where>
       <if test="state != null">
            state = #{state}
       if>
       <if test="title != null">
           AND title like #{title}
       if>
       <if test="author != null and author.name != null">
           AND author_name like #{author.name}
       if>
     where>
    select>

    where要素は1つ以上のif条件に値がある場合にのみ「WHERE」句を挿入することを知っている.また,最後の内容が「AND」または「OR」で始まると,where要素もそれらを除去する方法を知っている.
    where要素が通常のやり方でトランプされていない場合は、trim要素をカスタマイズして目的の機能をカスタマイズすることができます.たとえば、where要素と等価なカスタムtrim要素は、次のとおりです.
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
     ...
    trim>

    prefixOverridesプロパティは、パイプで区切られたテキストシーケンスを無視します(この例のスペースも必要です).その結果、prefixOverridesプロパティで指定したすべてのコンテンツが削除され、prefixプロパティで指定したコンテンツが挿入されます.
    同様に、文を動的に更新するためのソリューションをsetと呼びます.set要素は、更新が必要なカラムを動的に含み、他のカラムを切り捨てるために使用することができる.例:
    <update id="updateAuthorIfNecessary">
     update Author
       <set>
         <if test="username != null">username=#{username},if>
         <if test="password != null">password=#{password},if>
         <if test="email != null">email=#{email},if>
         <if test="bio != null">bio=#{bio}if>
       set>
     where id=#{id}
    update>

    ここでset要素はSETキーワードを動的に前置きし、条件文を使用すると生成された付与文の後ろにこれらのカンマが残る可能性が高いため、関係のないカンマも除去します.等価なカスタムtrim要素の様子に興味がある場合は、その正体です.
    <trim prefix="SET" suffixOverrides=",">
     ...
    trim>

    ここでは、接尾辞の値を無視し、接頭辞の値を一度に追加します.
    foreach動的SQLのもう一つの一般的な必要な操作は、IN条件文を構築する際に通常1つの集合を巡回する必要があることです.例:
    <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>

    foreach要素の機能は非常に強力で、要素内の集合項目とインデックス変数を宣言する集合を指定できます.また、開閉一致する文字列を指定し、反復の間に区切り記号を配置することもできます.この要素はインテリジェントなので、余分な区切り文字を偶然追加することはありません.リスト、コレクションなどの反復可能なオブジェクトと、任意の辞書または配列オブジェクトをforeachにコレクションパラメータとして渡すことができます.反復可能なオブジェクトまたは配列を使用する場合、indexは現在の反復の回数であり、itemの値は今回の反復で取得された要素である.辞書(またはMap.Entryオブジェクトのセット)を使用する場合、indexはキー、itemは値です.
    ここでは、XMLプロファイルとXMLマッピングファイルに関する議論を完了しました.次のセクションでは、作成したマッピングから最大の利益を得るためにJava APIについて詳しく説明します.
    Bindbind要素はOGLL式から変数を作成してコンテキストにバインドできます.例:
    <select id="selectBlogsLike" resultType="Blog">
     <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
     SELECT * FROM BLOG
     WHERE title LIKE #{pattern}
    select>

    Multi-db vendor support「_databaseId」変数を構成するdatabaseIdProviderは、ダイナミックコードで使用できます.これにより、異なるデータベース・ベンダーに基づいて特定の文を構築できます.たとえば、次の例です.
    <insert id="insert">
     <selectKey keyProperty="id" resultType="int" order="BEFORE">
       <if test="_databaseId == 'oracle'">
         select seq_users.nextval from dual
       if>
       <if test="_databaseId == 'db2'">
         select nextval for seq_users from sysibm.sysdummy1"
       if>
     selectKey>
     insert into users values (#{id}, #{name})
    insert>

    微信の公衆番号に注目:ITははははは(it_haha)、もっと多くの内容を勉強します.