Mybatis 動態(tài)SQL編寫

Mybatis學習

mybatis http://www.mybatis.org/mybatis-3/zh/index.html

動態(tài)SQL

  • MyBatis的加強大在于他的動態(tài)SQL
  • 動態(tài) SQL 元素和 JSTL 或基于類似 XML 的文本處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間了解。MyBatis 3 大大精簡了元素種類,現(xiàn)在只需學習原來一半的元素便可。MyBatis 采用功能強大的基于 OGNL 的表達式來淘汰其它大部分元素。
  • if(簡單的條件判斷)
  • choose(when,otherwize),想到與Java中的switch,與Jstl中的choose類似
  • trim(對包含的內(nèi)容加prefix或suffix等)
  • where(主要簡化sql語句中的where條件判斷,智能處理and or,不必擔心多余導致語法錯誤)
  • set(用于update 更新)
  • foreach(sql 中的 in 語句,查詢時特別管用)

if

if就是簡單的條件判斷,利用if語句我們可以實現(xiàn)某些簡單的條件選擇。動態(tài) SQL 通常要做的事情是有條件地包含 where 子句的一部分

<select id="findUser" parameterType="User" resultMap="User">
    select  id ,username,age from  user where 1=1
    <if test="username!=null and username!=''">
        and username=#{username}
    </if>
</select>

choose(when,otherwize)

when元素表示當when中的條件滿足的時候就輸出其中的內(nèi)容,跟JAVA中的switch效果差不多的是按照條件的順序,當when中有條件滿足的時候,
就會跳出choose,即所有的when和otherwise條件中,只有一個會輸出,當所有的我很條件都不滿足的時候就輸出otherwise中的內(nèi)容

<select id="chooseTest" parameterType="User" resultMap="User">
    select  id,username,age where i=1
    <choose>
        <when test="username!=null and username!=''">
            and username=#{username}
        </when>
        <otherwise>
            and age=#{age}
        </otherwise>
        
    </choose>     
</select>

trim(prefix,suffix),代替where

trim元素的主要功能是可以在自己包含的內(nèi)容前加上某些前綴,也可以在其后加上某些后綴,與之對應的屬性是prefix和suffix;可以把包含內(nèi)容的首部某些內(nèi)容覆蓋,即忽略,也可以把尾部的某些內(nèi)容覆蓋,對應的屬性是prefixOverrides和suffixOverrides;正因為trim有這樣的功能,所以我們也可以非常簡單的利用trim來代替where元素的功能

<select id="trimTest" parameterType="User" resultMap="User">
    select id,username,age form user
    <trim prefix="where" prefixOverrides="and | or">
        <if test="username!=null and username.length()>0">
            username like CONCAT(CONCAT('%',#{usrname}),'%')
        </if>
        <if test="age!=null and age!=''">
            and age=#{age}
        </if>
    </trim>
</select>

trim代替set標簽

if/trim代替set(判斷參數(shù)) - 將實體類不為空的屬性更新

<update id="updateUser" parameterType="User" >
    update  user
    <trim prefix="set" suffixOverrides=",">
        <if test="username!=null">
            username=#{username},
        </if>
        <if test="age!=null">
            age=${age}
        </if>
    </trim>
    <where>
        id=${id}
    </where>
</update>

set

set元素主要是用在更新操作的時候,它的主要功能和where元素其實是差不多的,主要是在set標簽包含的語句前輸出一個set。如果包含的語句是以逗號結(jié)束的話將會把該逗號忽略。如果set包含的內(nèi)容為空的話則會出錯。有了set元素我們就可以動態(tài)的更新那些修改了的字段,而不用每次更新全部字段

<update id="updateUser" parameterType="User">
    update user 
    <set>
        <if test="username!=null">
          username=#{username}  
        </if>
    </set>
    where id=${id}
</update>

foreach

foreach的主要用在構(gòu)建in條件中,它可以在SQL語句中進行迭代一個集合。foreach元素的屬性主要有item,index,collection,open,separator,close

  • item 表示集合中的每一個元素進行迭代時的別名
  • index 指定一個名字,用于表示迭代過程中每次迭代的位置
  • open 表示語句以什么開始
  • separator 表示在每次進行迭代之間以什么符號作為分隔符
  • close 表示以什么結(jié)束
  • collection 最關(guān)鍵的也是最容易出錯的,該屬性必須指定且在不同情況下屬性值不一樣
    • 如果傳入的是單參數(shù)且參數(shù)類型是一個List的時候,collection屬性值為list
    • 如果傳入的是單參數(shù)結(jié)參數(shù)類型是一個array數(shù)組的時候,collection的屬性值為array
    • 如果傳入的參數(shù)是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數(shù)也可以封裝成map,實際上如果你在傳入?yún)?shù)的時候,在MyBatis里面也是會把它封裝成一個Map的,map的key就是參數(shù)名,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map里面的key
  • list類型
<select id="foreachList" resultMap="User">
    select * from user where id in
    <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

// public List<User> foreachList(List<Integer> ids);
  • array數(shù)組類型
<select id="foreachArray" resultMap="User">
    select * from user where id in
    <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

// public List<User> foreachArray(int[] ids);
  • Map 封裝
<select id="foreacherMap" resultType="User">
    select * from user where username like CONCAT(CONCAT('%',#{username}),'%') and  id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

<!--代碼實現(xiàn)-->
@Test  
public void foreachMap() {  
    SqlSession session = Util.getSqlSessionFactory().openSession();  
    UserMapper userMapper = session.getMapper(UserMapper.class);  
    final List<Integer> ids = new ArrayList<Integer>();  
    ids.add(1);  
    ids.add(2);  
    ids.add(3);  
    Map<String, Object> params = new HashMap<String, Object>();  
    params.put("ids", ids);  
    params.put("username", "張三");  
    List<User> users = userMapper.foreachMap(params);  
    for (User user : users)  
        System.out.println(user);  
    session.close();  
}  

Mybatis防止SQL注入

Mybatis是啟用SQL預編譯功能的,底層實現(xiàn)原理:是JDBC中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種“準備好”的方式不僅能提高安全性,而且在多次執(zhí)行同一個SQL時,能夠提高效率。原因是SQL已編譯好,再次執(zhí)行時無需再編譯。

  • #{}:相當于JDBC中的PreparedStatement,是經(jīng)過預編譯的,是安全
  • ${}:輸出變量的值,會直接參與SQL編譯,是未經(jīng)過預編譯的,僅僅是取變量的值,存在SQL注入,是非安全
<select id="getUserById" parameterType="int" resultType="User">
    select id,username,age from user
    where id=#{id}
</select>

這里,parameterType表示了輸入的參數(shù)類型,resultType表示了輸出的參數(shù)類型。回應上文,如果我們想防止SQL注入,理所當然地要在輸入?yún)?shù)上下功夫.當輸入?yún)?shù)是打印出的sql是:

SELECT id,username,age FROM user WHERE id=?

不管輸入什么參數(shù),打印出的SQL都是這樣的。這是因為MyBatis啟用了預編譯功能,在SQL執(zhí)行前,會先將上面的SQL發(fā)送給數(shù)據(jù)庫進行編譯;執(zhí)行時,直接使用編譯好的SQL,替換占位符“?”就可以了。因為SQL注入只能對編譯過程起作用,所以這樣的方式就很好地避免了SQL注入的問題


以下將 #{} 換成 ${},給參數(shù)"id"賦值2,打印sql如下

SELECT id,username,age FROM user WHERE id=2

差異

// id=3,username=admin or 1=1

select * from user where id=#{id} and username=${username}

<!--執(zhí)行如下-->
select * from where id=? and username=admin or 1=1

//以上執(zhí)行時會執(zhí)行or這樣就存在安全問題
//這里用戶username=id

select * from user order by ${username}

<!--執(zhí)行如下-->
select * from user order by id

//顯然,這樣是無法阻止SQL注入的
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,239評論 0 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,697評論 18 399
  • 又到交作業(yè)的時候了,上次承諾的十一點之前睡覺,也只是做到了一半。之后確實也在實施,十點左右就睡覺了,早上5點多起床...
    louise楊琴閱讀 342評論 2 1
  • 整部劇給人一種灰蒙蒙的感覺,哪種感覺就像黑云壓城城欲催,憋悶的讓人窒息,所有人都是佝僂著背,雙手向前,仿佛隨時都準...
    冰箱里的蘋果汁閱讀 98評論 0 0
  • 上帝予使人滅亡,必定會使人瘋狂。 在最近一個星期,自己感覺被世界拋棄,完全像發(fā)瘋一樣去參與項目投資,認為每個項目都...
    半坡居士泉城閱讀 241評論 2 0

友情鏈接更多精彩內(nèi)容