Mybatis中#{}與${}的區別

前言

在開發中使用Mybatis常用到#{}與${},依舊有不少開發者對兩者的使用不是很清晰,正所謂好記性不如爛筆頭,特此總結一下。javascript

在mybatis中動態 sql 是其主要特性之一,在 mapper 中定義的參數傳到 xml 中以後,在執行操做以前 mybatis 會對其進行動態解析。mybatis 提供了兩種支持動態 sql 的語法:#{} 以及 $ {},其最大的區別則是#{}方式可以很大程度防止sql注入(安全),${}方式沒法防止Sql注入。什麼??不懂什麼是Sql注入?額。。。Sql注入指的是程序解析時會將你傳入的參數做爲原來SQL語句的一部分,打亂原來SQL的結構,而一般咱們只是須要傳入一個參數而已.java

完全理解SQL注入

什麼?還不懂SQL注入,我湖了QAQ。。。那就來個最簡單的例子:通常開發,確定是在前臺有兩個輸入框,一個用戶名,一個密碼,會在後臺裏,讀取前臺傳入的這兩個參數,拼成一段SQL,例如: select count(1) from tab where usesr=userinput and pass = passinput,把這段SQL鏈接數據後,看這個用戶名/密碼是否存在,若是存在的話,就能夠登錄成功了,若是不存在,就報一個登錄失敗的錯誤。對吧。
可是有這樣的狀況,這段SQL是根據用戶輸入拼出來,若是用戶故意輸入可讓後臺解析失敗的字符串,這就是SQL注入,例如,用戶在輸入密碼的時候,輸入 '''' ' or 1=1'', 這樣,後臺的程序在解析的時候,拼成的SQL語句,多是這樣的: select count(1) from tab where user=userinput and pass='' or 1=1; 看這條語句,能夠知道,在解析以後,用戶沒有輸入密碼,加了一個恆等的條件 1=1,這樣,這段SQL執行的時候,返回的 count值確定大於1的,若是程序的邏輯沒加過多的判斷,這樣就可以使用用戶名 userinput登錄,而不須要密碼。
防止SQL注入,首先要對密碼輸入中的單引號進行過濾,再在後面加其它的邏輯判斷,或者不用這樣的動態SQL拼sql

關於 # { }

一、#{}表示一個佔位符號 至關於 jdbc中的 ? 符號
#{}實現的是向prepareStatement中的預處理語句中設置參數值,sql語句中#{}表示一個佔位符即?安全

二、#{}將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:select * from user where id= #{user_id},若是傳入的值是11,那麼解析成sql時的值爲where id="11"mybatis

三、若是sql語句中只有一個參數,此時參數名稱能夠隨意定義
若是sql語句有個參數,此時參數名稱應該是與當前表關聯[實體類的屬性名]或則[Map集合關鍵字],不能隨便寫,必須對應!以下圖app

在這裏插入圖片描述

關於$ { }

一、$ {}將傳入的數據直接顯示生成在sql中。如:select * from user where id= $ {user_id},若是傳入的值是11,那麼解析成sql時的值爲where id=11測試

二、$ {value}value值有限制只能寫對應的value值不能隨便寫,由於${}不會自動進行jdbc類型轉換code

三、簡單來講,在JDBC不支持使用佔位符的地方,均可以使用${}xml

Mybatis中#{}與${}的區別

簡單來講區別就是對象

#{}方式可以很大程度防止sql注入(安全),${}方式沒法防止Sql注入

JDBC能使用佔位符的地方,最好優先使用#{}

JDBC不支持使用佔位符的地方,就只能使用${},典型狀況就是 動態參數

好比 有兩張表,分別是emp_2017emp_2018 .若是須要在查詢語句中 動態指定表名,就只能使用${}

<select>
      select *  from emp_ ${year}
<select>

再好比MyBatis 排序時使用order by 動態參數時,此時也只能使用${}

<select>
       select  *  from dept order by ${name}
</select>

代碼案例

通常# {}與$ {}用的比較多的地方是模糊查詢方面,因此下面來一個模糊查詢的案例

使用#{}案例

一、映射文件

在User.xml配置文件中添加以下內容:

<!-- 若是返回多個結果,mybatis會自動把返回的結果放在list容器中 -->
    <!-- resultType的配置和返回一個結果的配置同樣 -->
    <select id="queryUserByUsername1" parameterType="string"
        resultType="cn.itcast.mybatis.pojo.User">
        SELECT * FROM `user` WHERE username LIKE #{username}
    </select>

二、測試程序

MybatisTest中添加測試方法以下:

@Test
    public void testQueryUserByUsername1() throws Exception {
        // 4. 建立SqlSession對象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 5. 執行SqlSession對象執行查詢,獲取結果User
        // 查詢多條數據使用selectList方法
        List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");

        // 6. 打印結果
        for (Object user : list) {
            System.out.println(user);
        }

        // 7. 釋放資源
        sqlSession.close();
    }

測試效果以下圖:
在這裏插入圖片描述

使用$ {}案例

一、映射文件:

在User.xml配置文件中添加以下內容:

<!-- 若是傳入的參數是簡單數據類型,${}裏面必須寫value -->
    <select id="queryUserByUsername2" parameterType="string"
        resultType="cn.itcast.mybatis.pojo.User">
        SELECT * FROM `user` WHERE username LIKE '%${value}%'
    </select>

2.測試程序:
MybatisTest中添加測試方法以下:

@Test
public void testQueryUserByUsername2() throws Exception {
    // 4. 建立SqlSession對象
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 5. 執行SqlSession對象執行查詢,獲取結果User
    // 查詢多條數據使用selectList方法
    List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");

    // 6. 打印結果
    for (Object user : list) {
        System.out.println(user);
    }

    // 7. 釋放資源
    sqlSession.close();
}

固然兩個案例效果一致!

若是本文對你有一點點幫助,那麼請點個讚唄,謝謝~

最後,如有不足或者不正之處,歡迎指正批評,感激涕零!若是有疑問歡迎留言,絕對第一時間回覆!

歡迎各位關注個人公衆號,一塊兒探討技術,嚮往技術,追求技術,說好了來了就是盆友喔...

在這裏插入圖片描述

相關文章
相關標籤/搜索