當前位置: 妍妍網 > 碼農

被拷打已老實!面試官問我 #{} 和 ${} 的區別

2024-06-26碼農

引言:在使用 MyBatis 進行資料庫操作時, #{} ${} 的區別是面試中常見的問題,對理解如何在 MyBatis 中安全有效地處理 SQL 語句至關重要。正確使用這兩種占位符不僅影響套用的安全性,還涉及到效能最佳化。

題目

#{} 和 ${} 的區別是什麽?

推薦解析

預編譯與直接替換

面試官問了我這個問題,直接把我問老實了,求放過,趕忙來寫下以下思考:

1) #{} :使用 #{} 時,MyBatis 為 SQL 語句的參數生成一個預編譯語句,並透過參數占位符( ? )來代替實際的參數值。這種方式是安全的,因為它防止了 SQL 隱碼攻擊,參數值在發送到資料庫之前不會被解析為 SQL 的一部份。

如果你有一個查詢使用者的操作,你可以這樣寫:

SELECT * FROMusersWHEREid = #{userId}

2) ${} :相反,使用 ${} 時,參數值被直接替換到 SQL 語句中。這種方式雖然靈活,可以動態替換表名、列名等 SQL 語句的組成部份,但卻可能導致 SQL 註入問題,因為參數值如果包含惡意的 SQL 程式碼也會被執行。

如果你需要動態地選擇表名或列名,可以這樣使用:

SELECT * FROM ${tableName}

效能考慮

對於效能我得出以下思考:

1) #{} 效能優勢:由於使用預編譯的 SQL 語句,資料庫可以重用相同結構的 SQL 語句,減少編譯次數,提高執行效率。

2) ${} 效能問題:可能導致每次都要編譯新的 SQL 語句,因為 SQL 結構可能因為參數的不同而改變。

型別處理

琢磨琢磨我又發現了新大陸!型別處理~

1) #{} 型別處理:MyBatis 可以根據參數的 Java 型別自動推斷資料庫型別,處理日期、列舉等復雜型別的轉換。

2) ${} 型別處理:不進行型別轉換,將參數視為純文本,直接嵌入到 SQL 語句中。

魚聰明 AI 的回答:

魚聰明 AI 地址:https://www.yucongming.com/

#{}(參數占位符)

  • 預編譯 #{} 運算式使得參數在 SQL 語句中以占位符 ? 的形式出現。這意味著 SQL 語句會被預編譯並多次執行,參數值在執行時繫結。這種方式對於資料庫效能最佳化至關重要,因為預編譯可以減少資料庫編譯SQL的次數,提高執行效率。

  • 防止 SQL 註入 :由於參數不是直接拼接到 SQL 語句中,而是作為一個繫結的值傳遞給預編譯的 SQL 語句,因此 #{} 防止了 SQL 註入的風險。使用者輸入被當作字串處理,不會被執行為 SQL 程式碼的一部份。

  • 型別安全 :MyBatis 能夠根據 Java 型別自動推斷出相應的 SQL 型別。例如,如果你傳遞一個 Java Date 物件,MyBatis 會適當地處理它與 SQL 日期型別之間的轉換。

  • ${} (SQL 字串拼接)

  • 直接替換 :使用 ${} 時,參數值會在解析 SQL 語句之前直接替換到 SQL 字串中。這意味著你可以透過 ${} 插入動態表名、列名或者其他 SQL 片段,如動態排序條件。

  • 高風險 ${} 由於是直接將參數內容拼接到 SQL 語句中,所以存在 SQL 註入的風險。如果參數值來自不可控的使用者輸入,那麽可能被註入惡意的 SQL 程式碼。

  • 靈活性 :盡管風險較高, ${} 在某些場景下是必要的。特別是在 SQL 語句的某些部份無法透過預編譯實作,如動態改變表名或某些資料庫函式和命令, ${} 提供了必要的靈活性。

  • 推薦文章和書籍

    文章:https://zhuanlan.zhihu.com/p/86293659

    書籍:【 Java 核心技術卷 I 】

    歡迎交流

    當討論 MyBatis 中的 #{} ${} 占位符時,我們可以從以下幾個角度深入探討它們的概念、區別和實際套用,以便更好地理解它們在資料庫操作中的作用:

    1)什麽是 #{} ${} ?它們在 MyBatis 中有什麽套用?

    2) #{} ${} 的工作原理是什麽?

    3) #{} ${} 在實際套用中的選擇標準是什麽?

    點燃求職熱情!每周持續更新,海量面試題和大廠面經等你挑戰!趕緊關註面試鴨公眾號,輕松備戰秋招和暑期實習!

    往期推薦