天天看點

動态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 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>           

這段代碼的意思就是,如果有角色id就以角色id查詢,有使用者名字就以使用者名字查詢,若都沒有就全部查詢,這和我們之前JDBC中where條件加1==1的意思是一樣的

修改接口中的方法

public List 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 * FROM USER
<where>
<if test="userName!=null and userName!=''">
   AND userName LIKE concat('%',#{userName},'%')
    </if>
    <if test="userRole!=null">
        AND userRole=#{userRole}
    </if>
</where>           

使用if+trim實作多條件查詢

trim元素也會自動識别其标簽是否有傳回值,若有傳回值,會在自己包含前後加上某些字首(比如我們的修改語句加set),也可在其後加上某些字尾(就像我們的修改語句最後一般會有個修改的條件) 後續我們會詳細的講字首字尾的使用方法

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>           

prefix:字首,作用是通過自動識别是否有傳回值後,在trim包含的内容上加上字首,如此處的 where

suffix:字尾,作用是在trim包含的内容上加上字尾

prefixOverrides:對于trim包含内容的首部進行指定内容(如此處的"and | or")的忽略

suffixOverrides:對用trim包含的内容的首尾進行指定内容的忽略

使用動态SQL實作更新操作

==使用if+set改造更新操作==

set元素主要用于更新操作,它的主要功能和where元素差不多,主要是在包含的語句前面輸出一個set,若包含的語句逗号結尾,自動忽略逗号

在映射檔案中編寫修改語句

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}           

==下面我們用if+trim修改SQl語句==

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>           

屬性的意思上面也都說過了,大家可以翻到上面看一下

使用foreach完成複雜查詢

上面我們已經講過動态SQL的if,where,trim,set元素來處理一些簡單查詢操作,那麼對于一些SQL語句中含有in條件,我們就需要使用foreach标簽

foreach主要用在建構in條件中,在sql語句中疊代一個集合。它的主要屬性有,item、index、

collection、separator、close、open。下面我們通過示例給大家進行詳細介紹

1.MyBatis入參為數組類型的foreach類型

編寫接口

public List getUserByRoleId_foreach_array(Integer[] roleIds);

<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>           
SELECT * FROM USER WHERE userRole IN
<foreach collection="array" item="roleIds" open="(" separator="," close=")">
    #{roleIds}
</foreach>           

編寫測試

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 getUserByRoleId_foreach_list(List roleList);

<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>           
SELECT * FROM USER WHERE userRole IN
<foreach collection="list" item="roleIds" open="(" separator="," close=")">
    #{roleIds}  
</foreach>           
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 getUserByConditionMap_foreach_map(Map conditionMap);

SELECT * FROM USER WHERE gender=#{gender} AND userRole IN
<foreach collection="roleIds" item="roleMap" open="(" separator="," close=")">        
        #{roleMap}
</foreach>           
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 getUserList_choose(@Param("userName")String userName,@Param("userRole")Integer roleId,

@Param("userCode")String userCode,@Param("creationDate")Date creationDate);           
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>           

when元素:當其test屬性中條件滿足的時候,就會執行,一旦有一個條件滿足,則跳出choose

otherwise元素:當when中所有條件都不滿足的時候,就會執行otherwise中的内容