1、#{}是預編譯處理,$ {}是字符串替換
(1)#{} 表示一個佔位符,採用preparedStatement給佔位符設置值,自動進行java類型和jdbc類型轉換,進行預編譯處理,#{}可以有效防止sql注入(預編譯是提前對SQL語句進行編譯,而其後注入的參數將不會再進行編譯)
(2)${} 表示字符串替換,通過${}可以將parameterType或實體 傳入的內容拼接在sql中且不進行jdbc類型轉換
(3)舉例說明二者區別,現在有如下SQL:
select count(1) from user where user_name = #{userName} and password = #{password}
使用#{}時,會進行jdbc類型轉換,根據屬性 自動加上單引號
select count(1) from user where user_name = 'admin' and password = '123456';
而${}不會進行jdbc類型轉換,只是簡單的替換, 顯然有語法錯誤,但是可以利用其進行sql注入
select count(1) from user where user_name = admin and password = 123456;
2、SQL注入舉例離說明
SQL注入就是利用現有應用程序,將(惡意)的SQL命令注入到後臺數據庫執行一些惡意的操作。比如說,在登錄過程中,利用上面的語句到數據庫中查找用戶名/密碼是否存在,如果存在就登錄成功,如果不存在就登錄失敗。
若使用${},惡意用戶在表單中的用戶名文本框中輸入的是'admin',密碼框中輸入的是 ' ' or 1 = 1 加了一引號和一個恆成立的條件,那麼,傳到數據庫中的sql就是:
select count(1) from user where user_name = 'admin' and user_password = ' ' or 1=1
登錄成功,該惡意用戶是可以登錄系統的! 這就是SQL注入,惡意攻擊
而如果使用#{}是不會出現這種情況的,#{}默認會給輸入的值加上引號,密碼錯誤,登錄失敗
select count(1) from user where user_name = ''admin'' and user_password ='' ' or 1=1'
3、既然有了#{}爲什麼還需要${}
#{}並不適用一些其他場景,比如要根據參數名動態排序,需要傳入的參數是字段名,使用#{} 被解析成order by 'age' ,顯然達不到排序目的。而此時就用到了${}進行字符串替換操作,即sql解析成 order by age