欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

為什么MyBatis中常用#{}而不使用${}

 更新時(shí)間:2025年09月11日 08:32:13   作者:Leaton Lee  
本文主要介紹了為什么MyBatis中常用#{}而不使用${},文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言:一個(gè)真實(shí)的故事引發(fā)的技術(shù)思考

去年雙十一凌晨2點(diǎn),某公司用戶數(shù)據(jù)被刪,因?yàn)橐粋€(gè)MyBatis的${}使用失誤,導(dǎo)致黑客通過地址欄注入惡意SQL,直接清空了用戶表...

這就是我今天要講的:為什么MyBatis必須用#{},打死都不能用${}! 跟著我左手畫個(gè)SQL,右手寫個(gè)防注入,咱們用3個(gè)真實(shí)案例+6個(gè)代碼演示+1個(gè)完整項(xiàng)目,徹底講透這個(gè)價(jià)值百萬的安全問題!

一、新手村裝備:MyBatis參數(shù)傳遞基礎(chǔ)

1.1 參數(shù)占位符是什么?

在MyBatis的XML映射文件中,我們經(jīng)??吹竭@樣的SQL:

SELECT * FROM users WHERE id = #{userId}

這里的#{}就是MyBatis的參數(shù)占位符,相當(dāng)于JDBC中的PreparedStatement的 ‘?’。

1.2 兩種占位符對(duì)比表

特性#{}${}
參數(shù)類型任意類型只能字符串
SQL注入安全高危
預(yù)編譯支持不支持
參數(shù)替換方式帶引號(hào)替換直接拼接
使用場(chǎng)景值傳遞動(dòng)態(tài)表/列名

二、#{}與${}的"孿生兄弟"之謎

2.1 表面相似的代碼

先看兩個(gè)看似相同的查詢:

<!-- 使用#{} -->
<select id="getUserById" resultType="User">
    SELECT * FROM users WHERE id = #{userId}
</select>

<!-- 使用${} -->
<select id="getUserByIdUnsafe" resultType="User">
    SELECT * FROM users WHERE id = ${userId}
</select>

2.2 實(shí)際執(zhí)行的SQL

假設(shè)傳入userId=1:

  • #{}生成的SQL

    SELECT * FROM users WHERE id = ?

    參數(shù)1會(huì)被預(yù)編譯處理

  • ${}生成的SQL

    SELECT * FROM users WHERE id = 1

    直接拼接參數(shù)值

三、SQL注入:程序員的午夜兇鈴(代碼級(jí)演示)

3.1 模擬黑客攻擊場(chǎng)景

假設(shè)有個(gè)登錄查詢:

<!-- 危險(xiǎn)寫法! -->
<select id="login" resultType="User">
    SELECT * FROM users 
    WHERE username = '${username}'
    AND password = '${password}'
</select>

黑客輸入:

  • 用戶名:admin' --
  • 密碼:隨意填

生成的SQL

SELECT * FROM users 
WHERE username = 'admin' -- ' AND password = '123456'

效果:成功繞過密碼驗(yàn)證,直接登錄admin賬號(hào)!

3.2 使用#{}的正確姿勢(shì)

<select id="safeLogin" resultType="User">
    SELECT * FROM users 
    WHERE username = #{username}
    AND password = #{password}
</select>

此時(shí)無論輸入什么,參數(shù)都會(huì)被正確處理,無法注入。

四、執(zhí)行過程剖析:預(yù)編譯 vs 字符串拼接

4.1 MyBatis執(zhí)行流程對(duì)比圖

graph TD
    A[接收參數(shù)] --> B{占位符類型}
    B -->|#{}| C[生成PreparedStatement]
    B -->|${}| D[拼接完整SQL]
    C --> E[預(yù)編譯SQL]
    E --> F[安全執(zhí)行]
    D --> G[創(chuàng)建Statement]
    G --> H[風(fēng)險(xiǎn)執(zhí)行]

4.2 預(yù)編譯的三大優(yōu)勢(shì)

  • 防注入:將參數(shù)視為數(shù)據(jù)而非代碼
  • 性能提升:重復(fù)查詢復(fù)用編譯結(jié)果
  • 類型安全:自動(dòng)處理數(shù)據(jù)類型轉(zhuǎn)換

五、必須使用${}的三種特殊場(chǎng)景

雖然${}很危險(xiǎn),但在某些場(chǎng)景下不得不使用:

5.1 動(dòng)態(tài)表名查詢

<select id="selectByTable" resultType="map">
    SELECT * FROM ${tableName}
    WHERE id = #{id}
</select>

安全建議

  • 對(duì)tableName進(jìn)行白名單校驗(yàn)
  • 使用正則表達(dá)式過濾非法字符
// 校驗(yàn)示例
if (!tableName.matches("[a-zA-Z_0-9]+")) {
    throw new IllegalArgumentException("Invalid table name");
}

5.2 動(dòng)態(tài)排序字段

ORDER BY ${sortField} #{sortOrder}

安全方案

  • 使用枚舉限制可排序字段
  • 參數(shù)映射轉(zhuǎn)換
public enum SafeSortField {
    CREATE_TIME("create_time"),
    VIEW_COUNT("view_count");
    
    private final String columnName;
    // ...
}

六、綜合實(shí)戰(zhàn):電商訂單查詢系統(tǒng)

6.1 需求分析

  • 根據(jù)動(dòng)態(tài)條件查詢訂單
  • 支持多字段排序
  • 分頁(yè)查詢

6.2 安全實(shí)現(xiàn)方案

<select id="searchOrders" resultType="Order">
    SELECT * FROM orders
    <where>
        <if test="userId != null">
            user_id = #{userId}
        </if>
        <if test="startDate != null">
            AND create_time >= #{startDate}
        </if>
        <!-- 更多條件... -->
    </where>
    <!-- 安全排序方案 -->
    <if test="sortBy != null">
        ORDER BY 
        <choose>
            <when test="sortBy == 'TIME'">create_time</when>
            <when test="sortBy == 'AMOUNT'">total_amount</when>
            <otherwise>id</otherwise>
        </choose>
        ${sortOrder}
    </if>
    LIMIT #{pageSize} OFFSET #{offset}
</select>

七、靈魂拷問:你真的懂了嗎?

  • 當(dāng)需要?jiǎng)討B(tài)指定查詢列時(shí),應(yīng)該用哪種占位符?
  • 為什么說使用${}就像在SQL中開eval()?
  • 如何安全地實(shí)現(xiàn)動(dòng)態(tài)表頭導(dǎo)出功能?

把你的答案寫在評(píng)論區(qū),抽3位同學(xué)送《MyBatis深度解析》電子書!

八、終極總結(jié)(保存這張圖?。?/h2>
pie
    title 占位符使用準(zhǔn)則
    "#{} 常規(guī)參數(shù)" : 95%
    "${} 動(dòng)態(tài)表/列" : 4%
    "${} 其他場(chǎng)景" : 1%

三條黃金法則

  • 能用#{}堅(jiān)決不用${}
  • 必須用${}時(shí)要做好過濾
  • 所有用戶輸入必須使用#{}處理

九、FAQ精選

Q:為什么框架不直接禁用${}?
A:因?yàn)榇_實(shí)存在需要SQL動(dòng)態(tài)拼接的場(chǎng)景,框架需要保持靈活性,但安全責(zé)任在開發(fā)者。

Q:使用#{}會(huì)導(dǎo)致性能問題嗎?
A:恰恰相反,預(yù)編譯語(yǔ)句通常會(huì)提升性能,因?yàn)榭梢詮?fù)用執(zhí)行計(jì)劃。

Q:如何全局防止濫用?

A:可以通過自定義MyBatis插件,在發(fā)現(xiàn)${}時(shí)發(fā)出警告(需要團(tuán)隊(duì)規(guī)范配合)。

附錄:安全自查清單

  • 項(xiàng)目中沒有直接使用${}接收用戶輸入的案例
  • 所有動(dòng)態(tài)表/列操作都有白名單校驗(yàn)
  • 關(guān)鍵SQL語(yǔ)句都經(jīng)過安全審核
  • 定期進(jìn)行SQL注入漏洞掃描

到此這篇關(guān)于為什么MyBatis中常用#{}而不使用${}的文章就介紹到這了,更多相關(guān)MyBatis 常用#{}內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java?Git?Commit?Message使用規(guī)范

    Java?Git?Commit?Message使用規(guī)范

    這篇文章主要介紹了Java?Git?Commit?Message使用規(guī)范,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助
    2022-08-08
  • 如何解決創(chuàng)建maven工程時(shí),產(chǎn)生“找不到插件的錯(cuò)誤”問題

    如何解決創(chuàng)建maven工程時(shí),產(chǎn)生“找不到插件的錯(cuò)誤”問題

    這篇文章主要介紹了如何解決創(chuàng)建maven工程時(shí),產(chǎn)生“找不到插件的錯(cuò)誤”問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 關(guān)于springboot配置文件密文解密方式

    關(guān)于springboot配置文件密文解密方式

    這篇文章主要介紹了關(guān)于springboot配置文件密文解密方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 配置tjxCold(idea效率插件)的模版教程詳解

    配置tjxCold(idea效率插件)的模版教程詳解

    這篇文章主要介紹了配置tjxCold(idea效率插件)的模版教程詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • java代碼獲取數(shù)據(jù)庫(kù)表里數(shù)據(jù)的總數(shù)操作

    java代碼獲取數(shù)據(jù)庫(kù)表里數(shù)據(jù)的總數(shù)操作

    這篇文章主要介紹了java代碼獲取數(shù)據(jù)庫(kù)表里數(shù)據(jù)的總數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java與Http協(xié)議的詳細(xì)介紹

    Java與Http協(xié)議的詳細(xì)介紹

    這篇文章主要介紹了Java與Http協(xié)議的詳細(xì)介紹的相關(guān)資料,這里提供實(shí)例來幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • 淺談JVM內(nèi)存溢出原因和解決思路

    淺談JVM內(nèi)存溢出原因和解決思路

    本文主要介紹了淺談JVM內(nèi)存溢出原因和解決思路,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • java如何判斷一個(gè)對(duì)象是否為空對(duì)象

    java如何判斷一個(gè)對(duì)象是否為空對(duì)象

    本文主要介紹了java如何判斷一個(gè)對(duì)象是否為空對(duì)象,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java 圖表類庫(kù)詳解

    Java 圖表類庫(kù)詳解

    本文主要介紹了Java圖表類庫(kù)的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • IDEA教程之Activiti插件圖文詳解

    IDEA教程之Activiti插件圖文詳解

    這篇文章主要介紹了IDEA教程之Activiti插件圖文詳解,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論