最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

這就是我今天要講的:為什么MyBatis必須用#{},打死都不能用${}! 跟著我左手畫個SQL,右手寫個防注入,咱們用3個真實(shí)案例+6個代碼演示+1個完整項(xiàng)目,徹底講透這個價(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 兩種占位符對比表

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

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

2.1 表面相似的代碼

先看兩個看似相同的查詢:

<!-- 使用#{} -->
<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會被預(yù)編譯處理

  • ${}生成的SQL

    SELECT * FROM users WHERE id = 1

    直接拼接參數(shù)值

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

3.1 模擬黑客攻擊場景

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

<!-- 危險(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賬號!

3.2 使用#{}的正確姿勢

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

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

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

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

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ù)據(jù)而非代碼
  • 性能提升:重復(fù)查詢復(fù)用編譯結(jié)果
  • 類型安全:自動處理數(shù)據(jù)類型轉(zhuǎn)換

五、必須使用${}的三種特殊場景

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

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

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

安全建議

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

5.2 動態(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ù)動態(tài)條件查詢訂單
  • 支持多字段排序
  • 分頁查詢

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

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

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

三條黃金法則

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

九、FAQ精選

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

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

Q:如何全局防止濫用?

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

附錄:安全自查清單

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

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

相關(guān)文章

  • Spring中配置Transaction與不配置的區(qū)別及說明

    Spring中配置Transaction與不配置的區(qū)別及說明

    這篇文章主要介紹了Spring中配置Transaction與不配置的區(qū)別及說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • SpringCloud?Config之動態(tài)配置管理與高可用治理方式

    SpringCloud?Config之動態(tài)配置管理與高可用治理方式

    這篇文章主要介紹了SpringCloud?Config之動態(tài)配置管理與高可用治理方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • java中double類型運(yùn)算結(jié)果異常的解決方法

    java中double類型運(yùn)算結(jié)果異常的解決方法

    下面小編就為大家?guī)硪黄猨ava中double類型運(yùn)算結(jié)果異常的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 淺談Java泛型讓聲明方法返回子類型的方法

    淺談Java泛型讓聲明方法返回子類型的方法

    下面小編就為大家?guī)硪黄獪\談Java泛型讓聲明方法返回子類型的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java高版本Api在Android中的使用方法詳解

    Java高版本Api在Android中的使用方法詳解

    API(Application?Programming?Interface)應(yīng)用程序編程接口,java?API是一本程序員字典,是JDK提供給我們使用的類的說明文檔,下面這篇文章主要給大家介紹了關(guān)于Java高版本Api在Android中的使用方法,需要的朋友可以參考下
    2022-05-05
  • 淺析SpringBoot2底層注解@Conditional@ImportResource

    淺析SpringBoot2底層注解@Conditional@ImportResource

    這篇文章主要為大家介紹了SpringBoot2底層注解@Conditional@ImportResource的分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Java基礎(chǔ)之spring5新功能學(xué)習(xí)

    Java基礎(chǔ)之spring5新功能學(xué)習(xí)

    這篇文章主要介紹了Java基礎(chǔ)之spring5新功能學(xué)習(xí),文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • Java中byte輸出write到文件的實(shí)現(xiàn)方法講解

    Java中byte輸出write到文件的實(shí)現(xiàn)方法講解

    今天小編就為大家分享一篇關(guān)于Java中byte輸出write到文件的實(shí)現(xiàn)方法講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Java Vector類詳解及實(shí)例代碼

    Java Vector類詳解及實(shí)例代碼

    這篇文章主要介紹了Java Vector類詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Spring?Boot?集成JWT實(shí)現(xiàn)前后端認(rèn)證的示例代碼

    Spring?Boot?集成JWT實(shí)現(xiàn)前后端認(rèn)證的示例代碼

    小程序、H5應(yīng)用的快速發(fā)展,使得前后端分離已經(jīng)成為了趨勢,本文主要介紹了Spring?Boot?集成JWT實(shí)現(xiàn)前后端認(rèn)證,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論

萍乡市| 博客| 宝丰县| 台江县| 太原市| 沙洋县| 堆龙德庆县| 玉龙| 苍溪县| 达州市| 阳春市| 资溪县| 满城县| 屯门区| 宜川县| 江山市| 梁平县| 台北县| 松溪县| 平南县| 观塘区| 元朗区| 孟村| 宁都县| 德安县| 东港市| 南安市| 文登市| 鲁山县| 巴林右旗| 石屏县| 柳江县| 盐源县| 上林县| 临江市| 佛山市| 东阳市| 东方市| 海盐县| 赤城县| 平和县|