MyBatis中 #{} 和 ${} 區(qū)別

Mybatis的Mapper映射文件中,有兩種方式可以引用形參變量進(jìn)行取值: #{} 和 ${}
本文將簡述兩種方式的區(qū)別和適用場景

abstract.png

取值引用

#{} 方式

#{}: 解析為SQL時(shí),會將形參變量的值取出,并自動給其添加引號。
例如:當(dāng)實(shí)參username="Amy"時(shí),傳入下Mapper映射文件后

    ......
    <select id="findByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM user WHERE username=#{value}
    </select>
    ....

SQL將解析為:

    SELECT * FROM user WHERE username="Amy"

${} 方式

${}: 解析為SQL時(shí),將形參變量的值直接取出,直接拼接顯示在SQL中

例如:當(dāng)實(shí)參username="Amy"時(shí),傳入下Mapper映射文件后

    ......
    <select id="findByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM user WHERE username=${value}
    </select>
    ....

SQL將解析如下:

    SELECT * FROM user WHERE username=Amy

顯而該SQL無法正常執(zhí)行,故需要在mppaer映射文件中的${value}前后手動添加引號,如下所示:

    ......
    <select id="findByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM user WHERE username='${value}'
    </select>
    ....

SQL將解析為:

    SELECT * FROM user WHERE username='Amy'

SQL 注入

${}方式是將形參和SQL語句直接拼接形成完整的SQL命令后,再進(jìn)行編譯,所以可以通過精心設(shè)計(jì)的形參變量的值,來改變原SQL語句的使用意圖從而產(chǎn)生安全隱患,即為SQL注入攻擊。現(xiàn)舉例說明:

現(xiàn)有Mapper映射文件如下:

    ......
    <select id="findByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM user WHERE username='${value}'
    </select>
    ....

當(dāng) username = "' OR 1=1 OR '" 傳入后,${}將變量內(nèi)容直接和SQL語句進(jìn)行拼接,結(jié)果如下:

    SELECT * FROM user WHERE username='' OR 1=1 OR '';

顯而易見,上述語句將把整個(gè)數(shù)據(jù)庫內(nèi)容直接暴露出來了

#{}方式則是先用占位符代替參數(shù)將SQL語句先進(jìn)行預(yù)編譯,然后再將參數(shù)中的內(nèi)容替換進(jìn)來。由于SQL語句已經(jīng)被預(yù)編譯過,其SQL意圖將無法通過非法的參數(shù)內(nèi)容實(shí)現(xiàn)更改,其參數(shù)中的內(nèi)容,無法變?yōu)镾QL命令的一部分。故,#{}可以防止SQL注入而${}卻不行

適用場景

#{} 和 ${} 均適用場景

由于SQL注入的原因,${}和#{}在都可以使用的場景下,很明顯推薦使用#{}。這里除了上文的WHERE語句例子,再介紹一個(gè)LIKE模糊查詢的場景(username = "Amy"):

    <select id="findAddByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM user WHERE username LIKE '%${value}%'
    </select>

該SQL解析為:

    SELECT * FROM user WHERE username LIKE '%Amy%';

上述通過${}雖然可以實(shí)現(xiàn)對包含"Amy"對模糊查詢,但是不安全,可以改用#{},如下所示:

    <select id="findAddByName" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM USER WHERE username LIKE CONCAT('%', #{username}, '%')
    </select>

該SQL解析為下文所示,其效果和上文方式一致

    SELECT * FROM USER WHERE username LIKE CONCAT('%', 'Amy','%');

只能使用${}的場景

由于#{}會給參數(shù)內(nèi)容自動加上引號,會在有些需要表示字段名、表名的場景下,SQL將無法正常執(zhí)行?,F(xiàn)舉一例說明:

期望查詢結(jié)果按sex字段升序排列,參數(shù)String orderCol = "sex",mapper映射文件使用#{}:

    <select id="findAddByName3" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM USER WHERE username LIKE '%Am%' ORDER BY #{value} ASC
    </select>

則SQL解析及執(zhí)行結(jié)果如下所示,很明顯 ORDER 子句的字段名錯(cuò)誤的被加上了引號,致使查詢結(jié)果沒有按期排序輸出

    SELECT * FROM USER WHERE username LIKE '%Am%' ORDER BY 'sex' ASC;
result1.jpeg

這時(shí),現(xiàn)改為${}測試效果:

    <select id="findAddByName3" parameterType="String" resultMap="studentResultMap">
        SELECT * FROM USER WHERE username LIKE '%Am%' ORDER BY ${value} ASC
    </select>

則SQL解析及執(zhí)行結(jié)果如下所示:

    SELECT * FROM USER WHERE username LIKE '%Am%' ORDER BY sex ASC;
result2.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

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