目錄
#{}和${}這兩個語法是爲了動態傳遞參數而存在的,是Mybatis實現動態SQL的基礎,總體上他們的作用是一致的(爲了動態傳參),但是在編譯過程、是否自動加單引號、安全性、使用場景等方面有很多不同,下面詳細比較兩者間的區別:
一、區別彙總
1. 編譯過程
- #{} 是 佔位符 :動態解析 -> 預編譯 -> 執行
- ${} 是 拼接符 :動態解析 -> 編譯 -> 執行
2. 是否自動加單引號
- #{} 對應的變量會自動加上單引號
- ${} 對應的變量不會加上單引號
3. 安全性
- #{} 能防止sql 注入
- ${} 不能防止sql 注入
4. Mybatis默認值不同
- #{} 默認值 arg0、arg1、arg2 或 0、 1
- ${} 默認值param1、param2、param3
二、區別說明
上面列舉了 #{} 和 ${} 的區別,接下來結合代碼及SQL語句打印日誌進行說明:
關於SQL語句打印,如果是Spring Boot集成的Mybatis項目可以在application.yml文件中加入以下配置:
1. #{}
<select id="selectById" resultMap="roleResultMap">
select * from `role` where id = #{id}
</select>
#{}動態獲取id時,sql語句的打印顯示的是一個 “?” ,即佔位符。
2. ${}
<select id="selectById" resultMap="roleResultMap">
select * from `role` where id = ${id}
</select>
#{}動態獲取id時,sql語句的打印顯示的是一個 “1” ,沒有佔位符,直接顯示。
3. 關於安全性
主要指的就是防SQL注入,什麼是SQL注入?以上面的角色查詢爲例:
如果此時的傳參 name = "富貴 or name = 狗蛋",
select * from `role` where name = ${name}
因爲${}是拼接符,會直接替換,所以實際是:
select * from `role` where name = '富貴' or name = '狗蛋'
可以看到SQL語句的查詢規則已經改變,原本是查一個叫名字叫“富貴 or name=狗蛋”的角色 ,現在變成了查一個名字叫“富貴”或者叫“狗蛋”的角色,這種通過傳參就能改變SQL語句原本規則的操作就是SQL注入,這個在實際生產中當然是危險的,攻擊者可以把SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串中,欺騙服務器執行惡意的SQL命令。
可以看到,${} 直接拼接的方式可能引起SQL注入,不安全。那 #{} 爲啥就可以防止SQL注入呢?
select * from `role` where name = #{name}
因爲#{}是佔位符,所以實際是:
select * from `role` where name = '富貴 or name = 狗蛋'
可以看到, #{} 不會改變原本的SQL規則,佔位符 “?” 處會被完整替換,因此可以防止SQL注入。
4. 關於默認值
4.1 #{}
<select id="selectByNameAndOrgId" resultMap="roleResultMap">
select * from `role` where name = #{0} and org_id = #{1}
</select>
這裏用Mybatis默認的 0 和 1 來代替傳參,根據版本不同,也可能是用arg0、arg1、arg2,或者 param1 、param2 ,可以根據報錯信息進行修改,如下:
4.2 ${}
<select id="selectByNameAndOrgId" resultMap="roleResultMap">
select * from `role` where name = ${0} and org_id = ${1}
</select>
${} 時,用 0 和 1雖然不會報錯,但是會直接當成參數執行。一般默認參數是param1、param2...
<select id="selectByNameAndOrgId" resultMap="roleResultMap">
select * from `role` where name = ${param0} and org_id = ${param1}
</select>
三、如何選擇 #{} 和 ${}
- 能用 #{} 的地方就用 #{},儘量少用 ${}
- 表名作參數,或者order by 排序時用 ${}
- 傳參時參數使用@Param("")註解,如下:
Role selectById(@Param("id") String id);
List<Role> selectByNameAndOrgId(@Param("name") String name, @Param("orgId") String orgId);
以上就是 #{} 和 ${} 的區別與使用。