一、動態SQL概述
以前在使用JDBC操作數據時,如果查詢條件特別多,將條件串聯成SQL字符串是一件痛苦的事情。通常的解決方法是寫很多的if-else條件語句對字符串進行拼接,並確保不能忘了空格或在字段的最后省略逗號。MyBatis使用動態SQL來改善這種情形,動態SQL是基於OGNL的表達式,可方便我們在SQL語句中實現某些邏輯。用於實現動態SQL的元素如下。
- if:利用if實現簡單的條件選擇
- choose(when,otherwise):相當於Java中的switch語句,通常與when和otherwise搭配使用
- set:解決動態更新語句
- trim:可以靈活的去除多余的關鍵字
- foreach:迭代一個集合,通常用於in條件
二、if用法
在查詢條件不是很多並且較為固定的情況下,最好的解決方案是采用多參數直接入參的方式,這樣代碼比較清晰,可讀性強。如下
public interface UserMappper{ public List<User> getUserList(@Param("userName") String userName, @Param("userRole") Integer roleId); }
<select id="getUserList" resultMap="userList"> select u.*, r.roleName from smbms_user u, smbms_role r where u.userName like connect ('%', #{userName}, '%') and u.userRole=#{userRole} and u.userRole=r.id </select>
在上述代碼中,參數使用了@Param注解,並將參數roleId重命名為userRole
測試上述代碼,如下
- 在兩個條件都給出的情況下,如String userName="孫"; Integer roleId=3,此時會輸出正確結果;
- 若傳入的用戶角色roleId為空,即只按用戶名稱進行模糊查詢,如String userName="孫"; Integer roleId=null,此時輸出的結果不滿足需求:沒有輸入用戶角色的情況下,只根據用戶名稱進行模糊查詢的需求;
- 若傳入的用戶用戶名稱userName為“”(空字符串),roleId有值(roleId=3),此時結果是正確的;
針對上述這種某字段用戶輸入可能為空的情況,我們使用動態SQL的if元素來實現多條件查詢,如下
<select id="getUserList" resultMap="userList"> select u.*, r.roleName from smbms_user u, smbms_role r where u.userRole=r.id <if test="userRole != null"> and u.userRole = #{userRole} </if> <if test="userName != null and userName != ''"> and u.userName like concat('%', #{userName}, '%') </if> </select>
在上述代碼中,利用if元素實現簡單的條件判斷,if元素的test屬性表示進入if內需要滿足的條件。此時對於String userName="孫"; Integer roleId=null這種情況,輸出了正確結果。
三、if+where用法
單表查詢,考慮如下代碼
<select id="getUserList" resultType="User"> select * from smbms_user where <if test="userName != null and userName != ''"> u.userName like concat('%', #{userName}, '%') </if> <if test="userRole != null"> and u.userRole = #{userRole} </if> </select>
此時對於String userName=""; Integer roleId=3這種情況,會報錯,因為多了一個“and”。
針對這種and、where的處理,可使用動態SQL的where元素,where元素主要用來簡化SQL語句中的where條件判斷,並智能的處理and和or,不必擔心多余關鍵字導致的語法錯誤。如下
<select id="getUserList" resultType="User"> select * from smbms_user <where> <if test="userName != null and userName != ''"> and u.userName like concat('%', #{userName}, '%') </if> <if test="userRole != null"> and u.userRole = #{userRole} </if> </where> </select>
where元素標簽會自動標識其標簽內是否有返回值,若有,就插入一個where。此外,若該標簽返回的內容是以and或者or開頭的,會自動剔除。此時對於String userName=""; Integer roleId=3這種情況會正確輸出
四、if+trim用法
除了where元素之外,還可以使用trim元素來替代where元素,並實現與where元素相同的效果。
trim元素也會自動識別其標簽內是否有返回值,若有返回值,則在自己包含的內容前加上某些前綴,也可以在其后加上某些后綴,與之對應的屬性是prefix和suffix;trim也可把包含內容首部的某些內容覆蓋(即忽略),或者把尾部的某些內容覆蓋,與之對應的屬性是prefixOverrieds和suffixOverrieds。
<select id="getUserList" resultType="User"> select * from smbms_user <trim prefix="where" prefixOverrides="and | or"> <if test="userName != null and userName != ''"> and u.userName like concat('%', #{userName}, '%') </if> <if test="userRole != null"> and u.userRole = #{userRole} </if> </trim> </select>
prefixOverrides:對於trim包含內容的首部進行指定內容的忽略
