引言:在使用 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)
#{}
和
${}
在實際套用中的選擇標準是什麽?
點燃求職熱情!每周持續更新,海量面試題和大廠面經等你挑戰!趕緊關註面試鴨公眾號,輕松備戰秋招和暑期實習!
往期推薦