Mybatis中#{}與${}的使用
含義
#{}:為占位符
${}:為拼接符
區別:
用法
#{}:為參數占位符?,即sql預編譯
在程序運行時第一次操作數據庫之前,SQL語句已經被數據庫分析,編譯和優化,對應的執行計划也會緩存下來並允許數據庫已參數化的形式進行查詢,
當運行時動態地把參數傳給PreprareStatement時,即使參數里有敏感字符如 or '1=1'也數據庫會作為一個參數一個字段的屬性值來處理而不會作為一個SQL指令,如此,就起到了防止SQL注入的作用了!
${}為字符串替換, 即字符串拼接
執行流程
#{}:動態解析 --> 預編譯 --> 運行
${}: 動態解析 --> 編譯 -->運行
變量替換
#{}:變量替換是在DBMS(數據庫管理系統)中,會對對應的變量自動加上"
${}:變量替換動態解析過程,不會對對應的變量加上"
sql注入
#{}可以防止sql注入
${}不可以防止sql注入
${param}和#{param}的區別
${param}傳遞的參數會被當成sql語句中的一部分,比如傳遞表名,字段名 例子:(傳入值為id) order by ${param} 則解析成的sql為: order by id #{parm}傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號 例子:(傳入值為id) select * from table where name = #{param} 則解析成的sql為: select * from table where name = "id" 為了安全,能用#的地方就用#方式傳參,這樣可以有效的防止sql注入攻擊
sql注入簡介 直接上了百度的例子,感覺一看就清晰明了 某個網站的登錄驗證的SQL查詢代碼為: strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');" 惡意填入 userName = "1' OR '1'='1"; 與passWord = "1' OR '1'='1"; 時,將導致原本的SQL字符串被填為 strSQL = "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');" 也就是實際上運行的SQL命令會變成下面這樣的 strSQL = "SELECT * FROM users;" 這樣在后台帳號驗證的時候巧妙地繞過了檢驗,達到無賬號密碼,亦可登錄網站。所以SQL注入攻擊被俗稱為黑客的填空游戲。
預編譯具體細節區別
動態 sql 是 mybatis 的主要特性之一,在 mapper 中定義的參數傳到 xml 中之后,在查詢之前 mybatis 會對其進行動態解析。mybatis 為我們提供了兩種支持動態 sql 的語法:#{} 以及 ${}。
在下面的語句中,如果 username 的值為 zhangsan,則兩種方式無任何區別:
select * from user where name = #{name};
select * from user where name = ${name};
其解析之后的結果均為
select * from user where name = 'zhangsan';
但是 #{} 和 ${} 在預編譯中的處理是不一樣的。#{} 在預處理時,會把參數部分用一個占位符 ? 代替,變成如下的 sql 語句:
select * from user where name = ?;
而 ${} 則只是簡單的字符串替換,在動態解析階段,該 sql 語句會被解析成
select * from user where name = 'zhangsan';
以上,#{} 的參數替換是發生在 DBMS 中,而 ${} 則發生在動態解析過程中。
那么,在使用過程中我們應該使用哪種方式呢?
答案是,優先使用 #{}。因為 ${} 會導致 sql 注入的問題。看下面的例子:
select * from ${tableName} where name = #{name}
在這個例子中,如果表名為
user; delete user; --
則動態解析之后 sql 如下:
select * from user; delete user; -- where name = ?;
--之后的語句被注釋掉,而原本查詢用戶的語句變成了查詢所有用戶信息+刪除用戶表的語句,會對數據庫造成重大損傷,極大可能導致服務器宕機。
使用技巧
不論是單個參數還是多個參數,一律建議使用@param("")
能用#{}的地方盡量使用#{},減少${}
表名作為參數時,必須使用${}
order by 時,必須使用${}
使用${}時要注意何時加或不加單引號