#{}:表示一個占位符號,通過#{}可以實現preparedStatement向占位符中設置值,自動進行java類型和jdbc類型轉換,#{}可以有效防止sql注入。 #{}可以接收簡單類型值或pojo屬性值。
如果parameterType傳輸單個簡單類型值,#{}括號中可以是value或其它名稱。“%”#{name}”%”
${}:表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc類型轉換, ${}可以接收簡單類型值或pojo屬性值,
如果parameterType傳輸單個簡單類型值,${}括號中只能是value。
#{}是預編譯處理,$ {}是字符串替換。
預編譯的機制。預編譯是提前對SQL語句進行預編譯,而其后注入的參數將不會再進行SQL編譯。
我們知道,SQL注入是發生在編譯的過程中,因為惡意注入了某些特殊字符,最后被編譯成了惡意的執行操作。而預編譯機制則可以很好的防止SQL注入。
其實,區別就是如果使用#{},會將{}里面的傳入的值自動解析成為帶引號的值,比如:
select count(1) from tb_user where username = #{username} and password = #{password}
假如,此時傳入username傳入的值為admin,password傳入的值為123456,那么最后的sql就是:
select count(1) from tb_user where username = 'admin' and password = '123456';
#{}會解析成字符串,而${}就會這樣解析:
select count(1) from t_user where username = admin and password = 123456;
顯然,這是一個錯誤的sql語句,那么,什么叫SQL注入呢?為什么#{}可以有效的防止sql注入呢?
什么是SQL注入?
SQL注入就是利用現有應用程序,將(惡意)的SQL命令注入到后台數據庫執行一些惡意的操作
比如說,在登錄過程中,利用上面的語句到數據庫中查找用戶名/密碼是否存在,如果存在就登錄成功
而如果不存在就登錄失敗,如果說你后台使用的是${},惡意用戶在表單中的用戶名文本框中輸入的是'admin'
密碼框中輸入的是' ' or 1 = 1 加了一引號和一個恆成立的條件,那么,傳到數據庫中的sql就是:
select count(1) from t_user where user_name = 'admin' and user_password = ' ' or 1=1
如果程序沒有做其他的校驗,此時,該惡意用戶是可以登錄系統的! 這就是SQL注入,惡意攻擊
而如果使用#{}是不會出現這種情況的,#{}默認會給輸入的值加上引號,但是使用#{}在其他場景下並不適用
比如要使用到排序 order by #{} 傳入的參數應是表對應字段名,但是加上引號后就會解析成
order by 'age' 這樣就達不到排序的目的,而此時如果使用${}就可以達到排序的目的
即,sql解析成 order by age,根據age排序