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

MyBatis中#{}和${}的區(qū)別及底層原理、適用場景和安全風(fēng)險(xiǎn)

 更新時間:2026年04月25日 14:01:21   作者:想不明白的過度思考者  
本文詳細(xì)解析了MyBatis中#{}和${}的區(qū)別及其背后的底層原理、適用場景和安全風(fēng)險(xiǎn),#{}預(yù)編譯安全自動轉(zhuǎn)義,適用于業(yè)務(wù)參數(shù);{**拼接不安全需要手動加引號,主要用于動態(tài)表名、列名、排序關(guān)鍵字,使用時須做白名單校驗(yàn)

在 MyBatis 的面試和日常開發(fā)中,參數(shù)占位符 #{} ${} 的區(qū)別是繞不開的核心考點(diǎn)。很多同學(xué)只知道“#{} 安全,${} 不安全”,但其背后的底層原理適用場景卻一知半解。本文將通過底層分析、日志演示以及 SQL 注入實(shí)驗(yàn),帶你徹底搞定這個知識點(diǎn)。

一、 本質(zhì)區(qū)別速覽

特性#{}(井號)${}(刀樂/美元符號)
底層原理JDBC 預(yù)編譯占位符 ?純字符串拼接,直接替換
SQL 注入安全,自動轉(zhuǎn)義特殊字符危險(xiǎn),容易被惡意篡改
單引號處理自動添加,無需手動處理不自動加,字符串必須手動加 ''
性能高(預(yù)編譯 SQL 可重復(fù)利用)低(每次都需要重新解析)
使用場景99% 的業(yè)務(wù)參數(shù)(Where/Set 值)SQL 結(jié)構(gòu)關(guān)鍵字(表名、排序字段)

二、 核心原理詳解

1. #{}:預(yù)編譯模式(推薦)

當(dāng) MyBatis 遇到 #{xxx} 時,它會將 SQL 發(fā)送到數(shù)據(jù)庫進(jìn)行預(yù)編譯。在執(zhí)行階段,再通過 PreparedStatement 設(shè)置參數(shù)。
1. #{}:預(yù)編譯模式(推薦)

  • 示例代碼
@Select("select * from user_info where username = #{name}")
UserInfo queryByName(String name);

  • 打印日志(重點(diǎn))
    通過日志可以觀察到,SQL 中參數(shù)部分是 ? 占位符:
    PREPARE: select * from user_info where username = ?
  • 優(yōu)勢:由于 SQL 結(jié)構(gòu)已固定,傳入的參數(shù)只會被當(dāng)作“值”處理,不會破壞 SQL 語義,從而徹底杜絕 SQL 注入。

2. ${}:字符串拼接模式(慎用)

${} 會在 SQL 執(zhí)行前,直接把參數(shù)原封不動地替換進(jìn) SQL 語句中。

  • 示例代碼(報(bào)錯預(yù)警):
@Select("select * from user_info where username = ${name}")
UserInfo queryByName(String name);

  • 運(yùn)行結(jié)果:如果你傳入 admin,生成的 SQL 是 where username = admin。因?yàn)槿鄙賳我?,?shù)據(jù)庫會報(bào)錯。
  • 正確寫法:必須手動加引號:'${name}'

三、 SQL 注入(必考面試點(diǎn))

SQL 注入是指攻擊者通過在輸入框中填入 SQL 片段,篡改原有邏輯的行為。

注入場景:免密登錄

假設(shè)我們有一段使用 ${} 的危險(xiǎn)代碼:

SELECT * FROM user WHERE username = '${name}' AND pwd = '${pwd}'

  1. 正常操作:傳入用戶名 admin,密碼 123。
  2. 攻擊操作:攻擊者在用戶名框輸入 admin' -- ,密碼隨便寫。
  3. 最終生成的 SQL
SELECT * FROM user WHERE username = 'admin' -- ' AND pwd = 'xxx'

在 SQL 中,-- 代表注釋。這意味著 AND pwd = ... 的邏輯被直接注銷掉了!攻擊者無需密碼即可直接以管理員身份登錄。

結(jié)論絕不能使用 ${} 接收用戶輸入的參數(shù)!

四、 SQL 注入場景演示

控制層:UserTestController
注意自己所寫的類位置以及包

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserTestController {
    @Autowired
    private UserTestService userService;
    @RequestMapping("/login")
    public boolean login(String name, String password) {
        UserInfo userInfo = userService.queryUserByPassword(name, password);
        if (userInfo != null) {
            return true;
        }
        return false;
    }
}

業(yè)務(wù)層:UserTestService

import com.example.demo.mapper.UserInfoMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserTestService {
    @Autowired
    private UserInfoTestMapper userInfoMapper;
    public UserInfo queryUserByPassword(String name, String password) {
        List<UserInfo> userInfos = userInfoMapper.queryUserByPassword(name, password);
        if (userInfos != null && userInfos.size() > 0) {
            return userInfos.get(0);
        }
        return null;
    }
}

數(shù)據(jù)層:UserInfoTestMapper

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserInfoTestMapper {
    @Select("select username, `password`, age, gender, phone from user_info where username= '${name}' and password='${password}' ")
        List<UserInfo> queryUserByPassword(String name, String password);
}

啟動服務(wù),訪問:http://127.0.0.1:8080/login?name=admin&password=admin
程序正常運(yùn)行

 SQL 注入場景演示
接下來訪問SQL注?的代碼:
password設(shè)置為' or 1='1
拼接為:http://127.0.0.1:8080/login?name=admin&password=’ or 1='1
注意看網(wǎng)頁地址?。ò俜痔柡涂崭襁M(jìn)行了URL編碼,因?yàn)閁RL不允許直接添加特殊字符)
 SQL 注入場景演示_圖2

五、 ${} 的“唯一”合法使用場景

既然 ${} 這么危險(xiǎn),為什么不廢掉它?因?yàn)樗谔幚?SQL 結(jié)構(gòu)時無可替代:

  1. 動態(tài)表名
    SELECT * FROM ${tableName}#{} 無法用于表名,因?yàn)轭A(yù)編譯不支持表名占位)。
  2. 動態(tài)排序字段
    ORDER BY ${column} ${orderType}(如按 idcreate_time 排序,且指定 ASC/DESC)。

安全建議:在使用這些場景時,必須在 Service 層做白名單校驗(yàn),確保傳入的列名或表名是合法的。

六、 開發(fā)規(guī)范口訣

為了方便記憶,我們可以總結(jié)為一段口訣:

井號預(yù)編譯安全自帶引號,刀樂拼接危險(xiǎn)手動加引號;
業(yè)務(wù)參數(shù)全用井號,結(jié)構(gòu)關(guān)鍵字才用刀樂。

一句話總結(jié):
平時開發(fā)無腦用 #{};只有在需要動態(tài)傳遞表名、列名、排序關(guān)鍵字且已經(jīng)做好安全過濾的情況下,才考慮使用 ${}

到此這篇關(guān)于MyBatis中#{}和${}的區(qū)別及底層原理、適用場景和安全風(fēng)險(xiǎn)的文章就介紹到這了,更多相關(guān)MyBatis中#{}和${}的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Windows環(huán)境下安裝達(dá)夢數(shù)據(jù)庫的完整步驟

    Windows環(huán)境下安裝達(dá)夢數(shù)據(jù)庫的完整步驟

    達(dá)夢數(shù)據(jù)庫的安裝大致分為Windows和Linux版本,本文將以dm8 企業(yè)版 Windows_64位 環(huán)境為例,為大家介紹一下達(dá)夢數(shù)據(jù)庫的具體安裝步驟吧
    2025-03-03
  • 數(shù)據(jù)庫觸發(fā)器Trigger詳解

    數(shù)據(jù)庫觸發(fā)器Trigger詳解

    在數(shù)據(jù)庫管理系統(tǒng)中,觸發(fā)器(Trigger)是一種特殊的存儲過程,它在特定的事件發(fā)生時自動執(zhí)行,本文給大家介紹數(shù)據(jù)庫觸發(fā)器Trigger的相關(guān)知識,感興趣的朋友一起看看吧
    2025-05-05
  • node-mysql中防止SQL注入的方法總結(jié)

    node-mysql中防止SQL注入的方法總結(jié)

    大家都知道SQL注入對于網(wǎng)站或者服務(wù)器來講都是一個非常危險(xiǎn)的問題,如果這一方面沒處理好的話網(wǎng)站可能隨時給注入了,所以這篇文章就給大家總結(jié)了node-mysql中防止SQL注入的幾種常用做法,有需要的朋友們可以參考借鑒。
    2016-10-10
  • 復(fù)制數(shù)據(jù)庫表中兩個字段數(shù)據(jù)的SQL語句

    復(fù)制數(shù)據(jù)庫表中兩個字段數(shù)據(jù)的SQL語句

    今天為表新添加一個字段,但又想與表中的另一個字段值相同,由于數(shù)據(jù)過多想通過sql語句實(shí)現(xiàn),經(jīng)測試下面的這句話確實(shí)很好用
    2013-07-07
  • sql join on 用法

    sql join on 用法

    非常不錯使用join on實(shí)現(xiàn)數(shù)據(jù)庫字段的連接輸出效果。
    2009-07-07
  • mybatis映射XML文件詳解及實(shí)例

    mybatis映射XML文件詳解及實(shí)例

    這篇文章主要介紹了mybatis映射XML文件詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 干掉Navicat,這個數(shù)據(jù)庫管理工具真香

    干掉Navicat,這個數(shù)據(jù)庫管理工具真香

    這篇文章主要介紹了干掉Navicat,這個數(shù)據(jù)庫管理工具真香,本文詳細(xì)的介紹DataGrip的具體使用方法和實(shí)現(xiàn),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 使用DBeaver連接PostgreSQL實(shí)現(xiàn)方式

    使用DBeaver連接PostgreSQL實(shí)現(xiàn)方式

    DBeaver是一款功能強(qiáng)大的數(shù)據(jù)庫管理工具,支持多種數(shù)據(jù)庫,包括PostgreSQL,以下是使用DBeaver連接PostgreSQL的步驟:打開DBeaver,選擇創(chuàng)建連接,選擇PostgreSQL,輸入服務(wù)器信息,測試連接,最后點(diǎn)擊完成即可
    2025-11-11
  • DBeaver轉(zhuǎn)儲數(shù)據(jù)庫報(bào)錯問題解決辦法

    DBeaver轉(zhuǎn)儲數(shù)據(jù)庫報(bào)錯問題解決辦法

    DBeaver是一個通用的數(shù)據(jù)庫工具,支持MySQL、PostgreSQL、Oracle、SQLite、SQL Server等多種數(shù)據(jù)庫系統(tǒng),這篇文章主要介紹了DBeaver轉(zhuǎn)儲數(shù)據(jù)庫報(bào)錯問題的解決辦法,需要的朋友可以參考下
    2025-11-11
  • 檢查數(shù)據(jù)庫服務(wù)器是否正在運(yùn)行的常見方法小結(jié)

    檢查數(shù)據(jù)庫服務(wù)器是否正在運(yùn)行的常見方法小結(jié)

    在日常的數(shù)據(jù)庫操作和維護(hù)中,確保數(shù)據(jù)庫服務(wù)器正常運(yùn)行是至關(guān)重要的,本文整理了幾種常見的檢查數(shù)據(jù)庫服務(wù)器是否正在運(yùn)行的方法,需要的小伙伴可以了解下
    2025-04-04

最新評論

邵武市| 彭阳县| 芜湖市| 衡阳县| 东明县| 瓦房店市| 额尔古纳市| 肇庆市| 临泽县| 井研县| 厦门市| 聂拉木县| 湟中县| 财经| 南乐县| 长阳| 台北县| 中超| 大兴区| 信阳市| 巴里| 礼泉县| 台东县| 敦化市| 资源县| 松桃| 塘沽区| 海原县| 江永县| 伊金霍洛旗| 太湖县| 章丘市| 乃东县| 广丰县| 乌拉特后旗| 鄂伦春自治旗| 武义县| 肇州县| 长沙县| 黑龙江省| 麦盖提县|