Mybatis-動態 SQL

  • if 用法:

    • 在 WHERE 條件中使用 if

      publi class User {
          private Interger id;
          private String username;
          private String userEmail;
          
          // 省略其它代碼
      }
      
      <select id="selectByUser" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           WHERE username like concat('%', #{username}, '%')
             AND user_email = #{userEmail}    
      </select>
      

      當同時輸入 username 和 userEmail 兩個查詢條件時, 能夠查出正確的結果, 但是當只提供 username 參數時, 這時 userEmail 默認是 null, 這會導致 user_email = null 也成爲查詢條件, 因而查不出正確的結果. 可以採用 if 標籤來解決這個問題.

      <select id="selectByUser" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           WHERE 1 = 1
           <if test="username != null and username != ''">
              AND username like concat('%', #{username}, '%')
           </if>
           <if test="userEmail != null and userEmail != ''">
              AND user_email = #{userEmail}    
           </if>
      </select>
      
    • 在 UPDATE 更新列中使用 if:

      <update id="update">
          UPDATE user
             SET
             <if test="username != null and username != ''">
                  username= #{username},
             </if>
             <if test="userEmail != null and userEmail != ''">
                  userEmail= #{userEmail},
             </if>
                  id = #{id}
           WHERE  id = #{id} 
      </update>
      

    這樣通過 if 標籤就可以達到動態更新的目的. 這裏爲了確保最終產生的 SQL 語句沒有語法錯誤. 需要注意兩點: 第一點是每個 if 元素裏面的 SQL 語句後面都要添加逗號; 第二點是 where 關鍵字前面的 id = #{id}.

    • 在 INSERT 動態插入列中使用 if:

      <insert id="insert">
          INSERT INTO user(
                      id,
                  <if test="username != null and username != ''">
                      username,
                  </if>
                      user_email
                      )
               VALUES (
                      id,
                  <if test="username != null and username != ''">
                      #{username},
                  </if>
                      user_email
                      )
      </insert>
      

    這樣可以實現的效果是, 如果某一列的參數值不爲空, 就是用傳入的值, 如果傳入參數爲空, 就使用數據庫中的默認值, 而不使用傳入的空值. 這裏需要注意的是, 若列的部分增加 if 條件, 則 values 的部分也要增減相同的 if 條件.

  • choose 用法:

    • 在 SELECT 選擇中使用:

      <select id="selectByIdOrUsername" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           WHERE 1 = 1
           <choose>
              <when test="id != null">
                 AND id = #{id}
              </when>
              <when test="userName != null and userName != ''">
                 AND user_name = #{userName}
              </when>
              <otherwise>
                 AND 1 = 2
              </otherwise>
           </choose>
      </select>
      

    這裏一定要寫 otherwise 條件, 否則當所有條件都不滿足時, 所有的用戶都會被查詢出來.

  • where 用法:

    • SELECT 選擇中使用:

      <select id="selectByUser" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           <where>
               <if test="username != null and username != ''">
                  AND username like concat('%', #{username}, '%')
               </if>
               <if test="userEmail != null and userEmail != ''">
                  AND user_email = #{userEmail}    
               </if>
           </where
      </select>
      

      where 標籤的作用: 如果該標籤包含的元素中有返回值, 就插入一個 where; 如果 where 後面的字符串是以 AND 或 OR 開頭的, 就將它們剔除.

    • set 用法:

      • UPDATE 中的用法
      <update id="update">
          UPDATE user
            <set>
              <if test="username != null and username != ''">
                 username= #{username},
              </if>
              <if test="userEmail != null and userEmail != ''">
                 userEmail= #{userEmail},
              </if>
                 id = #{id},
            </set>
           WHERE id = #{id} 
      </update>
      

    set 標籤的作用: 如果該標籤包含的元素中有返回值, 就插入一個 set; 如果 set 後面的字符串是以逗號結尾的, 就將這個逗號剔除.

  • trim 用法:

    • where 標籤的 trim 實現:

      <trim prefix="WHERE" prefixOverrides="AND |OR ">
      </trim>
      
    • set 標籤的 trim 實現:

      <trim prefix="SET" suffixOverrides=",">
      </trim>
      
  • foreach 用法:
    foreach 可以對數組, Map 或 實現了 Iterable 接口的對象進行遍歷. 數組在處理的時候會轉化成 List 對象.

    • foreach 實現 in 集合:

      List<User> selectListByIds(List<Integer> ids);
      
      <select id="selectListByIds" resultType="study.User">
          SELECT id,
                 username,
                 userEmail
            FROM user
            <foreach collection="list" open="(" close=")" separator=",">
                 #{id}
            </foreach>
      </select>
      

    注意這裏 collection 的鍵是 list, 這裏是 Mybatis 爲 List 類型集合設置的默認鍵. Map 類型的默認鍵是 _parameter; Array 類型的默認鍵是 array.

      ```
      private Object wrapCollection(final Object object) {
          if (object instanceof Collection) {
              StrictMap<Object> map = new StrictMap<>();
              map.put("collection", object);
              if (Object instanceof List) {
                  map.put("list", object);
              }
              return map;
          } else if (object != null && object.getClass().isArray()) {
              StrictMap<Object> map = new StrictMap<>();
              map.put("array", object);
              return map;
          }
          return object;
      }
      ```
    
    • foreach 實現批量插入:

      <insert id="insertBatch">
          INSERT INTO user(
                      id, 
                      username,
                      user_email
                      )
               VALUES 
               <foreach collection="list" item="user" separator=",">
                      #{id},
                      #{username}
                      #{userEmail}
               </foreach>
      </insert>
      
    • foreach 實現動態 UPDATE:

      <update id="updateByMap">
          UPDATE user
             SET   
          <foreach collection="_parameter" item="val" index="key" separator=",">
              ${key} = #{val}
          </foreach>
           WHERE id = #{id}
      </update>
      
  • bind 用法:

    • bind 拼接查詢條件:

      <if test="username != null and username != ''">
          AND username like concat('%', #{username}, '%')
      </if>
      

      由於在各個數據庫中的函數可能存在差異, 所以這裏可以採用 bind 來拼接查詢條件.

      <if test="username != null and username != ''">
          <bind name="usernameLike" value="'%' + username + '%'"/>
          AND username LIKE #{usernameLike}
      </if>
      
  • 多數據庫支持:

    • mybatis-config.xml 增加配置:

      <databaseIdProvider type="DB_VENDOR"/>
      
    • mapper.xml 增加 databaseId 屬性

      <select id="selectByUser" databseId="mysql" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           WHERE username LIKE concat('%', #{username}, '%')   
      </select>
      
      <select id="selectByUser" databseId="oracle" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           WHERE username LIKE '%'||#{username}||'%'   
      </select>
      

      也可以使用 if 標籤配合默認的上下文中的 _databaseId 參數這種寫法去實現.

      <select id="selectByUser" databseId="oracle" resultType="study.User">
          SELECT id,
                 username,
                 user_email
            FROM user
           <where>
              <if test="username != null and username != ''">
                  <if test="_databaseId == 'mysql'">
                      AND username LIKE concat('%', #{username}, '%') 
                  </if>
                  <if test="_databaseId == 'oracle'">
                      AND username LIKE '%'||#{username}||'%'   
                  </if>
              </if>
           </where>
      </select>
      
  • OGNL 用法:

    • 在 Xml 中調用類的靜態方法:
    public class StringUtil {
        public static boolean isEmpty(String str) {
            return str == null || str.length() == 0;
        }
        
        public static boolean isNotEmpty(String str) {
            return !StringUtil.isEmpty(str);
        }
    }
    
    <if test="@study.StringUtil@isNotEmpty(username)">
        AND username LIKE concat('%', #{username}, '%') 
    </if>
    
  • 參考:
    [1] : MyBatis從入門到精通

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章