1. 程式人生 > >MyBatis 筆記(五)——動態 SQL

MyBatis 筆記(五)——動態 SQL

在開發中,經常會遇到要執行的 SQL 語句其實並不是固定,而是隨條件的變化而變化的。對於這種情況 MyBatis 也有解決方案。

隨條件變化的 SQL

先看一個固定的 SQL 語句,查詢指定 name 和 age 的人:

<resultMap id="PersonMap" type="Person">
    <id column="id" jdbcType="INTEGER" property="pid" javaType="int"/>
    <result column="name" jdbcType="VARCHAR" property="pname"
javaType="String"/> <result column="age" jdbcType="INTEGER" property="page" javaType="int"/> </resultMap> <select id="selectWithNothing" parameterType="Person" resultMap="PersonMap"> SELECT id, name, age FROM person WHERE name = #{name} and age = #{age} </select>

上面的 SQL 當 name 或 age 為空時,該查詢將會丟擲異常。

if 標籤

在不確定查詢條件是否為空時,可以用 if 標籤進行檢查:

<select id="selectWithIf" parameterType="Person" resultMap="PersonMap">
    select id, name, age
    from person
    where 1=1

    <if test="pname != null and pname != '' ">
        and name = #{pname}
    </if
> <if test="page != null and page != 0 "> and age &lt; #{page} </if> </select>

注意:where 後的 1 = 1 建議加上,這樣可以避免無一條件滿足時,最終的 SQL 語句中 where 後面沒有過濾條件。

呼叫方法如下:

public void selectWithIf(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    Person entity = new Person();
    entity.setPname("Jimmy");
    List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIf", entity);

    System.out.println(persons);
    sqlSession.close();
}

where - if 標籤

SELECT 語句中,為了簡化 if 標籤,可以使用 where - if 標籤組合使用:

<select id="selectWithIfWhere" parameterType="Person" resultMap="PersonMap">
  selectid, name, age
  from person

  <where>
      <if test="pname != null and pname != '' ">
          and name = #{pname}
      </if>
      <if test="page != null and page != 0 ">
          and age &lt; #{page}
      </if>
  </where>
</select>

where - if 標籤中,SQL 語句可以加上 and,MyBatis 會自動識別。

呼叫方法:

public void selectWithIfWhere(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    Person entity = new Person();
    entity.setPname("Jimmy");
    entity.setPage(30);
    List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIfWhere", entity);

    System.out.println(persons);
    sqlSession.close();
}

set - if 標籤

UPDATE 語句中,為了簡化 if 標籤,可以使用 set - if 標籤組合使用:

<update id="updateWithIfSet" parameterType="Person">
    updateperson

    <set>
        <if test="pname != null and pname != '' ">
            name = #{pname}
        </if>
        <if test="page != null and page != 0 ">
            and age = #{page}
        </if>
    </set>

    where id = #{pid}
</update>

set 標籤為自動為每個 if 標籤中的 SQL 語句加上逗號隔開。

呼叫方法:

public void updateWithIfSet(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession(true);
    Person entity = new Person();
    entity.setPid(2);
    entity.setPname("Bill");
    int result = sqlSession.update("edu.wzm.mybatis.mapping.PersonMapper.updateWithIfSet", entity);

    System.out.println(result);
    sqlSession.close();
}

trim - if 標籤

還有一種更強大的組合標籤 trim - if,它既可以處理 SELECT語句,又可以處理 UPDATE 語句。如代替上面的 where - if 標籤:

<select id="selectWithIfTrim" parameterType="Person" resultMap="PersonMap">
    SELECT id,name, age
    FROM person

    <trim prefix="WHERE" prefixOverrides="AND|OR">
        <if test="pname != null and pname != '' ">
            name = #{pname}
        </if>
        <if test="page != null and page != 0 ">
            age &lt; #{page}
        </if>
    </trim>
</select>

代替上面的 set - if 標籤:

<update id="updateWithIfTrim" parameterType="Person">
    UPDATE person

    <trim prefix="SET" prefixOverrides=",">
        <if test="pname != null and pname != '' ">
            name = #{pname}
        </if>
        <if test="page != null and page != 0 ">
            age &lt; #{page}
        </if>
    </trim>

    WHERE id = #{pid}
</update>

choose - when 標籤

上面的標籤都是一組條件的中的每一個條件要麼可選,要麼不選。但是對於一組互斥的條件,只能從中選擇一個,那麼上面的標籤就不好處理了,需要使用 choose - when 標籤:

<select id="selectWithChooseWhen" parameterType="Person" resultMap="PersonMap">
    SELECT id, name, age
    FROM person

    <where>
        <choose>
            <when test="pname != null and pname != '' ">
                name = #{pname}
            </when>
            <when test="page != null and page != 0 ">
                AND age &lt; #{page}
            </when>
            <otherwise>

            </otherwise>
        </choose>
    </where>
</select>

注意choose - when 標籤類似於 if - elseif - else

迴圈

對於動態 SQL 非常必須的,主是要迭代一個集合,通常是用於 IN 條件。List 例項將使用 “list” 做為鍵,陣列例項以 “array” 做為鍵。

foreach 元素是非常強大的,它允許你指定一個集合,宣告集合項和索引變數,它們可以用在元素體內。它也允許你指定開放和關閉的字串,在迭代之間放置分隔符。這個元素是很智慧的,它不會偶然地附加多餘的分隔符。

注意:可以傳遞一個List例項或者陣列作為引數物件傳給是MyBatis。當你這麼做的時候,MyBatis 會自動將它包裝在一個 Map中,用名稱在作為鍵。List 例項將會以 “list” 作為鍵,而陣列例項將會以 “array” 作為鍵。

陣列

使用陣列例項作為引數:

<select id="selectWithForeachArray" resultMap="PersonMap">
    SELECT id, name, age
    FROM person
    WHERE id IN

    <foreach collection="array" item="pid" open="(" separator="," close=")">
      #{pid}
    </foreach>
</select>

呼叫方法:

public void selectWithForeachArray(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    int[] pids = {1, 3};
    List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachArray", pids);

    System.out.println(persons);
    sqlSession.close();
}

列表

使用列表作為引數:

<select id="selectWithForeachList" resultMap="PersonMap">
    SELECT id, name, age
    FROM person
    WHERE id IN

    <foreach collection="list" item="pid" open="(" separator="," close=")">
        #{pid}
    </foreach>
</select>

呼叫方法:

public void selectWithForeachList(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    List<Integer> pids = new ArrayList<>();
    pids.add(2);
    pids.add(3);
    List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachList", pids);

    System.out.println(persons);
    sqlSession.close();
}