動態SQL
使用動態SQL完成多條件查詢
動態SQl是MyBatis的一個強大的特性,在使用JDBC操作資料時,如果查詢條件過多,將字串聯成SQL語句是比較麻煩的一件事,且容易出錯,有了動態SQL我們就可以使用動態SQL,動態SQL基於OGNL表示式,可使我們方便地在SQL語句中實現某些邏輯。好了廢話不多說,接下來我們看下示例
==在這裡我們還是使用上一篇文章使用的示例,只是修改一下,大家可以先看一下上一篇文章==
用於實現動態SQL的元素如下
- if:利用if實現簡單的條件選擇
- choose(when,otherwise):相當於Java中的switch語句,通常與when和otherwise搭配
- where:簡化SQL語句中where的條件判斷。
- set:解決動態更新語句 trim:可以靈活地去除多餘的關鍵字
- foreach:迭代一個集合,通常用於in條件
使用if做多條件查詢
修改UserMapper.xml檔案
<select id="getUserList" resultMap="userList"> SELECT u.*,r.roleName FROM USER u,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>
這段程式碼的意思就是,如果有角色id就以角色id查詢,有使用者名稱字就以使用者名稱字查詢,若都沒有就全部查詢,這和我們之前JDBC中where條件加1==1的意思是一樣的
修改介面中的方法
public List<User> getUserList(@Param("userRole")Integer roleId,@Param("userName")String userName);
新增測試
public void testQuery(){ SqlSession sqlSession=null; try{ sqlSession=MyBatisUtil.createSqlSession(); //這裡我們就寫兩個引數,看看會出現什麼結果 List<User> userList=sqlSession.getMapper(UserMapper.class).getUserList(2,null); for (User user: userList) { System.out.println(user.getUserName()); } }catch (Exception ex){ ex.printStackTrace(); }finally { MyBatisUtil.closeSqlSession(sqlSession); } }
使用where
where元素主要用來簡化SQL語句中的where條件判斷,並能智慧地處理and和or,如果有多餘的and或者or where會智慧的去除,我們可以把他和if聯合起來一塊使用
修改UserMapper.xml
<!--注意開啟自動對映--> <select id="getUserList" resultType="User"> SELECT * FROM USER <where> <if test="userName!=null and userName!=''"> AND userName LIKE concat('%',#{userName},'%') </if> <if test="userRole!=null"> AND userRole=#{userRole} </if> </where> </select>
使用if+trim實現多條件查詢
trim元素也會自動識別其標籤是否有返回值,若有返回值,會在自己包含前後加上某些字首(比如我們的修改語句加set),也可在其後加上某些字尾(就像我們的修改語句最後一般會有個修改的條件) 後續我們會詳細的講字首字尾的使用方法
修改UserMapper.xml
<select id="getUserList" resultType="User"> SELECT * FROM USER <trim prefix="where" prefixOverrides="and | or"> <if test="userName!=null and userName!=''"> AND userName LIKE concat('%',#{userName},'%') </if> <if test="userRole!=null"> AND userRole=#{userRole} </if> </trim> </select>
prefix:字首,作用是通過自動識別是否有返回值後,在trim包含的內容上加上字首,如此處的 where
suffix:字尾,作用是在trim包含的內容上加上字尾
prefixOverrides:對於trim包含內容的首部進行指定內容(如此處的"and | or")的忽略
suffixOverrides:對用trim包含的內容的首尾進行指定內容的忽略
使用動態SQL實現更新操作
==使用if+set改造更新操作==
set元素主要用於更新操作,它的主要功能和where元素差不多,主要是在包含的語句前面輸出一個set,若包含的語句逗號結尾,自動忽略逗號
在對映檔案中編寫修改語句
<update id="modify" parameterType="User"> UPDATE USER <set> <if test="userCode!=null">userCode=#{userCode},</if> <if test="userName!=null">userName=#{userName},</if> <if test="userPassword!=null">userPassword=#{userPassword},</if> <if test="gender!=null">gender=#{gender},</if> <if test="phone!=null">phone=#{phone},</if> <if test="address!=null">address=#{address},</if> <if test="userRole!=null">userRole=#{userRole},</if> <if test="modifyBy!=null">modifyBy=#{modifyBy},</if> <if test="modifyDate!=null">modifyDate=#{modifyDate},</if> <if test="birthday!=null">birthday=#{birthday},</if> </set> WHERE id=#{id} </update>
==下面我們用if+trim修改SQl語句==
<update id="modify" parameterType="User"> UPDATE USER <trim prefix="set" suffixOverrides="," suffix="where id=#{id}"> <if test="userCode!=null">userCode=#{userCode},</if> <if test="userName!=null">userName=#{userName},</if> <if test="userPassword!=null">userPassword=#{userPassword},</if> <if test="gender!=null">gender=#{gender},</if> <if test="phone!=null">phone=#{phone},</if> <if test="address!=null">address=#{address},</if> <if test="userRole!=null">userRole=#{userRole},</if> <if test="modifyBy!=null">modifyBy=#{modifyBy},</if> <if test="modifyDate!=null">modifyDate=#{modifyDate},</if> <if test="birthday!=null">birthday=#{birthday},</if> </trim> </update>
屬性的意思上面也都說過了,大家可以翻到上面看一下
使用foreach完成複雜查詢
上面我們已經講過動態SQL的if,where,trim,set元素來處理一些簡單查詢操作,那麼對於一些SQL語句中含有in條件,我們就需要使用foreach標籤
foreach主要用在構建in條件中,在sql語句中迭代一個集合。它的主要屬性有,item、index、
collection、separator、close、open。下面我們通過示例給大家進行詳細介紹
1.MyBatis入參為陣列型別的foreach型別
編寫介面
public List<User> getUserByRoleId_foreach_array(Integer[] roleIds);
修改UserMapper.xml
<resultMap id="userMapByRole" type="User"> <id property="id" column="id"/> <result property="userCode" column="userCode"/> <result property="userName" column="userName"/> </resultMap> <select id="getUserByRoleId_foreach_array" resultMap="userMapByRole"> SELECT * FROM USER WHERE userRole IN <foreach collection="array" item="roleIds" open="(" separator="," close=")"> #{roleIds} </foreach> </select>
編寫測試
public void testGetUserByRoleId_foreach_array(){ SqlSession sqlSession=null; List<User> userList=new ArrayList<User>(); Integer[] roleIds={2,3}; try{ sqlSession=MyBatisUtil.createSqlSession(); userList=sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleIds); }catch (Exception ex){ ex.printStackTrace(); }finally { MyBatisUtil.closeSqlSession(sqlSession); } for (User user: userList) { System.out.println(user.getUserName()+"\t"+user.getAddress()); } }
各個屬性的意思:
item:表示集合中每一個元素進行迭代時的名稱
index:指定一個名稱,用於表示在迭代過程中,每次迭代到的位置
open:表示該語句以什麼開始(in語句以"("開始)
separator:表示在每次迭代之間以什麼符號做分割符
close:表示該語句以什麼結束
collection:必須指定,入參為單參型別是List時,collection屬性值為list;入參為單參是陣列時,為 array;若為多參,需封裝Map
parameterType可以不配置,MyBatis會自動封裝為Map傳入
2.MyBatis入參為List型別的foreach迭代
在介面中新增方法
public List<User> getUserByRoleId_foreach_list(List<Integer> roleList);
修改UserMapper.xml
<resultMap id="userMapByRole" type="User"> <id property="id" column="id"/> <result property="userCode" column="userCode"/> <result property="userName" column="userName"/> </resultMap> <select id="getUserByRoleId_foreach_list" resultMap="userMapByRole"> SELECT * FROM USER WHERE userRole IN <foreach collection="list" item="roleIds" open="(" separator="," close=")"> #{roleIds} </foreach> </select>
編寫測試
public void testGetUserByRoleId_foreach_array(){ SqlSession sqlSession=null; List<User> userList=new ArrayList<User>(); List<Integer> nums=new ArrayList<Integer>(); nums.add(1); nums.add(2); try{ sqlSession=MyBatisUtil.createSqlSession(); userList=sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_list(nums); }catch (Exception ex){ ex.printStackTrace(); }finally { MyBatisUtil.closeSqlSession(sqlSession); } for (User user:userList) { System.out.println(user.getUserName()+"\t"+user.getAddress()); } }
3.MyBatis入參為Map型別的foreach迭代
在上面兩個示例中,我們都是以一個引數入參的,如果我們查詢管理員並且是男性該怎麼寫那,這種多引數入參我們就可以使用Map入參的方式
編寫介面中的方法
public List<User> getUserByConditionMap_foreach_map(Map<String,Object> conditionMap);
修改UserMapper.xml
<select id="getUserByConditionMap_foreach_map" resultMap="userMapByRole"> SELECT * FROM USER WHERE gender=#{gender} AND userRole IN <foreach collection="roleIds" item="roleMap" open="(" separator="," close=")"> #{roleMap} </foreach> </select>
編寫測試
public void testGetUserByRoleId_foreach_array(){ SqlSession sqlSession = null; List<User> userList = new ArrayList<User>(); Map<String, Object> param = new HashMap<String, Object>(); List<Integer> roleList = new ArrayList<Integer>(); roleList.add(1); roleList.add(2); param.put("gender",2); param.put("roleIds",roleList); try { sqlSession = MyBatisUtil.createSqlSession(); userList = sqlSession.getMapper(UserMapper.class).getUserByConditionMap_foreach_map(param); } catch (Exception ex) { ex.printStackTrace(); } finally { MyBatisUtil.closeSqlSession(sqlSession); } for (User user : userList) { System.out.println(user.getUserName() + "\t" + user.getAddress()); } }
總結:
1.MyBatis接受的引數型別:基本型別、物件、List、陣列、Map
2.無論MyBatis的入參是哪種資料型別,MyBatis都會將引數放在一個Map中
對於單引數入參的情況:
若入參為基本型別:變數名作為key,變數值為value,此時生成的Map只有一個元素若入參為物件:物件的屬性名做key,屬性值為value
若入參為List:預設“list”作為key,該List即為value
若入參為陣列:預設“array”作為key,該陣列即為value
若入參為Map:鍵值不變
choose(when,otherwise)
choose可以選擇其中一種情況下的查詢結果,流程和switch相同,通常都是搭配when,otherwise使用
編寫介面方法
public List<User> getUserList_choose(@Param("userName")String userName,@Param("userRole")Integer roleId, @Param("userCode")String userCode,@Param("creationDate")Date creationDate);
修改UserMapper.xml
<select id="getUserList_choose" resultType="User"> SELECT * from USER WHERE 1=1 <choose> <when test="userName!=null and userName!=''"> AND userName=#{userName} </when> <when test="userCode!=null and userCode!=''"> AND userCode LIKE concat('%',#{userCode},'%') </when> <when test="userRole!=null and userRole!=''"> AND userRole=#{userRole} </when> <otherwise> AND YEAR(creationDate)=YEAR(#{creationDate}) </otherwise> </choose> </select>
各個屬性的意思:
when元素:當其test屬性中條件滿足的時候,就會執行,一旦有一個條件滿足,則跳出choose
otherwise元素:當when中所有條件都不滿足的時候,就會執行otherwise中的內容
多敲幾遍你就會明白其中的奧義,可能我寫的文章還有許多地方不足,有什麼問題大家可以留言討論
by安心