首先看一下下面兩個sql語句的區別:
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap"> select id, username, password, role from user where username = #{username,jdbcType=VARCHAR} and password = #{password,jdbcType=VARCHAR} </select>
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap"> select id, username, password, role from user where username = ${username,jdbcType=VARCHAR} and password = ${password,jdbcType=VARCHAR} </select>
mybatis中的#和$的區別:
1、#將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。
如:where username=#{username},如果傳入的值是111,那么解析成sql時的值為where username="111", 如果傳入的值是id,則解析成的sql為where username="id".
2、$將傳入的數據直接顯示生成在sql中。
如:where username=${username},如果傳入的值是111,那么解析成sql時的值為where username=111;
3、針對上面的sql,如果傳入的值是;drop table user;,
那么第一條用#{}的sql解析為:select id, username, password, role from user where username=";drop table user;"
那么第二條用${}的sql解析為:select id, username, password, role from user where username=;drop table user;
這時候已經sql注入了。
3、#方式能夠很大程度防止sql注入,$方式無法防止Sql注入。
4、$方式一般用於傳入數據庫對象,例如傳入表名和列名,還有排序時使用order by動態參數時需要使用$ ,ORDER BY ${columnName}
5、一般能用#的就別用$,若不得不使用“${xxx}”這樣的參數,要手工地做好過濾工作,來防止sql注入攻擊。
6、在MyBatis中,“${xxx}”這樣格式的參數會直接參與SQL編譯,從而不能避免注入攻擊。但涉及到動態表名和列名時,只能使用“${xxx}”這樣的參數格式。所以,這樣的參數需要我們在代碼中手工進行處理來防止注入。
【結論】在編寫MyBatis的映射語句時,盡量采用“#{xxx}”這樣的格式。若不得不使用“${xxx}”這樣的參數,要手工地做好過濾工作,來防止SQL注入攻擊。