1. 程式人生 > >Mybatis 中 ${} 和 #{} 區別

Mybatis 中 ${} 和 #{} 區別

1. #將傳入的資料都當成一個字串,會對自動傳入的資料加一個雙引號。如:order by #user_id#,如果傳入的值是111,那麼解析成sql時的值為order by "111", 如果傳入的值是id,則解析成的sql為order by "id".
  
2. $將傳入的資料直接顯示生成在sql中。如:order by $user_id$,如果傳入的值是111,那麼解析成sql時的值為order by user_id,  如果傳入的值是id,則解析成的sql為order by id.
  
3. #方式能夠很大程度防止sql注入。
  
4.$方式無法防止Sql注入。

5.$方式一般用於傳入資料庫物件,例如傳入表名.
  
6.一般能用#的就別用$.

MyBatis排序時使用order by 動態引數時需要注意,用$而不是#

字串替換
預設情況下,使用#{}格式的語法會導致MyBatis建立預處理語句屬性並以它為背景設定安全的值(比如?)。這樣做很安全,很迅速也是首選做法,有時你只是想直接在SQL語句中插入一個不改變的字串。比如,像ORDER BY,你可以這樣來使用:
ORDER BY ${columnName}
這裡MyBatis不會修改或轉義字串。

重要:接受從使用者輸出的內容並提供給語句中不變的字串,這樣做是不安全的。這會導致潛在的SQL注入攻擊,因此你不應該允許使用者輸入這些欄位,或者通常自行轉義並檢查。

mybatis本身的說明:

String Substitution

By default, using the #{} syntax will cause MyBatis to generate PreparedStatement properties and set the values safely against the PreparedStatement parameters (e.g. ?). While this is safer, faster and almost always preferred, sometimes you just want to directly inject a string unmodified into the SQL Statement. For example, for ORDER BY, you might use something like this:

ORDER BY ${columnName}
Here MyBatis won't modify or escape the string.

NOTE It's not safe to accept input from a user and supply it to a statement unmodified in this way. This leads to potential SQL Injection attacks and therefore you should either disallow user input in these fields, or always perform your own escapes and checks.

從上文可以看出:

1. 使用#{}格式的語法在mybatis中使用Preparement語句來安全的設定值,執行sql類似下面的:

PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,id);

這樣做的好處是:更安全,更迅速,通常也是首選做法。

2. 不過有時你只是想直接在 SQL 語句中插入一個不改變的字串。比如,像 ORDER BY,你可以這樣來使用:

ORDER BY ${columnName}

此時MyBatis 不會修改或轉義字串。

這種方式類似於:

    Statement st = conn.createStatement();
       
      ResultSet rs = st.executeQuery(sql);

這種方式的缺點是: 以這種方式接受從使用者輸出的內容並提供給語句中不變的字串是不安全的,會導致潛在的 SQL 注入攻擊,因此要麼不允許使用者輸入這些欄位,要麼自行轉義並檢驗。

小案例

前提條件

    1.採用mybatis map方式傳遞引數

    2.id 為 Integer型別    last_name為VARCHAR型別

寫法1

<select id="getByIdAndName" resultType="vip.fkandy.mybatis.ch22.bean.Employee" parameterType="map">
        select id,last_name as lastName , gender,email from t_employee where id = ${id} AND last_name = ${lastName}
</select>

生成SQL資訊如下:

2018-03-23 09:20:03,316 [main] DEBUG [vip.fkandy.mybatis.ch22.mapper.EmployeeMapper.getByIdAndName] - ==>  Preparing: select id,last_name as lastName , gender,email from t_employee where id = 1 AND last_name = joy 
2018-03-23 09:20:03,332 [main] DEBUG [vip.fkandy.mybatis.ch22.mapper.EmployeeMapper.getByIdAndName] - ==> Parameters: 

錯誤資訊如下:


說明:

    $是直接將內容拼接到SQL中,interger正常處理,VARCHAR型別報錯,因為在SQL執行的過程中VARCHAR型別需要加單引號

寫法2

<select id="getByIdAndName" resultType="vip.fkandy.mybatis.ch22.bean.Employee" parameterType="map">
        select id,last_name as lastName , gender,email from t_employee where id = #{id} AND last_name = #{lastName}
</select>

生成SQL資訊如下:

2018-03-23 09:28:30,919 [main] DEBUG [vip.fkandy.mybatis.ch22.mapper.EmployeeMapper.getByIdAndName] - ==>  Preparing: select id,last_name as lastName , gender,email from t_employee where id = ? AND last_name = ? 
2018-03-23 09:28:30,966 [main] DEBUG [vip.fkandy.mybatis.ch22.mapper.EmployeeMapper.getByIdAndName] - ==> Parameters: 1(Integer), joy(String)
2018-03-23 09:28:30,982 [main] DEBUG [vip.fkandy.mybatis.ch22.mapper.EmployeeMapper.getByIdAndName] - <==      Total: 1

說明:

Mybatis在處理#號的時候,會根據資料庫型別新增單引號,並且不會發生SQL注入問題

參考:http://www.cnblogs.com/baizhanshi/p/5778692.html