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

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

abstract.png

取值引用

#{} 方式

#{}: 解析為SQL時(shí),會(huì)將形參變量的值取出,并自動(dòng)給其添加引號(hào)。
例如:當(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無(wú)法正常執(zhí)行,故需要在mppaer映射文件中的${value}前后手動(dòng)添加引號(hào),如下所示:

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

SQL將解析為:

    SELECT * FROM user WHERE username='Amy'

SQL 注入

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

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

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

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

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

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

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

適用場(chǎng)景

#{} 和 ${} 均適用場(chǎng)景

由于SQL注入的原因,${}和#{}在都可以使用的場(chǎng)景下,很明顯推薦使用#{}。這里除了上文的WHERE語(yǔ)句例子,再介紹一個(gè)LIKE模糊查詢的場(chǎng)景(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%';

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

    <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','%');

只能使用${}的場(chǎng)景

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

期望查詢結(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ò)誤的被加上了引號(hào),致使查詢結(jié)果沒(méi)有按期排序輸出

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

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

    <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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

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