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从入门到精通

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