#{} 和 ${} 的區別--詳細

目錄

一、區別彙總

1.  編譯過程

2.  是否自動加單引號

3.   安全性

4.  Mybatis默認值不同

二、區別說明

1.  #{}

2.  ${}

3.  關於安全性

4.  關於默認值

4.1  #{}

4.2  ${}

三、如何選擇 #{} 和 ${}


#{}和${}這兩個語法是爲了動態傳遞參數而存在的,是Mybatis實現動態SQL的基礎,總體上他們的作用是一致的(爲了動態傳參),但是在編譯過程、是否自動加單引號、安全性、使用場景等方面有很多不同,下面詳細比較兩者間的區別:

一、區別彙總

1.  編譯過程

  1. #{} 佔位符 :動態解析 -> 預編譯 -> 執行
  2. ${} 拼接符 :動態解析 -> 編譯 -> 執行

2.  是否自動加單引號

  1. #{} 對應的變量自動加上單引號 
  2. ${} 對應的變量不會加上單引號 

3.   安全性

  1. #{}  防止sql 注入
  2. ${}  不能防止sql 注入

4.  Mybatis默認值不同

  1. #{} 默認值 arg0arg1arg2  或 0、 1
  2. ${} 默認值param1param2param3

二、區別說明

上面列舉了 #{} 和 ${} 的區別,接下來結合代碼及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默認的 01 來代替傳參,根據版本不同,也可能是用arg0arg1arg2,或者 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>

三、如何選擇 #{} 和 ${}

  1. 能用 #{} 的地方就用 #{},儘量少用 ${}
  2. 表名作參數,或者order by 排序時用 ${}
  3. 傳參時參數使用@Param("")註解,如下:

Role selectById(@Param("id") String id);
       List<Role> selectByNameAndOrgId(@Param("name") String name, @Param("orgId") String orgId);

 

以上就是 #{} 和 ${} 的區別與使用。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章