[Java MyBatis] #{}與${}的使用與區別(詳細)



前言

        最近在開始思考MyBatis中的一些細節,遇到不會的就找博客,發現這部分內容有所欠缺。雖然在這條路上我還是個新手,但每次遇到問題最常幫助我的都是這些陌生人的博客,這次就由我來吧。歡迎轉載,請標明出處。有名字就更好了


#{}與${}的使用

 #{}是占位符填充,如下當我們執行sql語句時會將sql語句中的 #{id} 替換成 ?號

UserDao.java 接口文件:

 User queryUserByUsername(@Param("username") String username);

UserDaoMapper.xml 映射文件:

 <select id="queryUserByUsername" resultMap="user_resultMap">
	 select id,username,password,gender,regist_time
	 from t_user
	 where username=#{username}
 </select>

執行后的sql語句:

	select id,username,password,gender,regist_time
    from t_user
    where username=?

${}是字符串拼接,多數情況下使用與#{}沒區別,但是有下面幾點要注意:

  1. 如果這個列是字符類型,我們要加引號,如where username='${username}'
  2. 如果傳入參數是簡單類型像是數字、字符串等要在UserDao.java中加@Param("username")否則${}取值會有問題
  3. 如果是一個引用類型的實例對象參數,那我們可以不加,如:
    User queryUserByUsername(@Param ("username") User user);

存在問題

使用${}當拼接sql片段時,有sql注入風險,外界參數會改變原有sql的語義,如:

 //sql注入
 String username = "zhangsan' or '1'='1";

注入后的sql語句:

 select id,username,password,gender,regist_time
 from t_user
 where username='zhangsan' or '1'='1'

這就導致了哪怕你數據庫中沒有這個用戶名也能成功查詢到數據。而使用 #{ } 它會將sql語義過濾,將 zhangsan' or '1'='1 當成一個普通字符串,可以規避sql注入的風險。所以原則上能不用sql拼接就不用sql拼接,那為什么還要有 ${ } 的存在呢?是因為在有些場景中 #{ } 不能使用,如我們要給查詢到的數據進行排序

 String rule="desc";
 String sql="select * from t_user order by id ?";

當我們在占位符上填充desc時,會導致sql語句語法出錯,這就涉及了占位符的使用原則

 //原則:填充數據,要和列相關
 select * from t_user where id=?
 inseret into t_user values(?,?,?)
 update t_user set username?,password=?

顯然desc與列無關,就會導致報錯

小技巧

MyBatisTest.java 測試方法

	@Test
	public void test(){
        UserDao mapper = MyBatisUtil.getMapper(UserDao.class);
        Integer sig=0;   //0:desc  1:asc
        if(sig==0){
        	mapper.queryUserUsers("desc");
        }else{
			mapper.queryUserUsers("asc");	
		} 
	}        

使用 ${ } 拼接sql片段的時候,用戶傳的內容只是一個依據,我們可以通過這個依據進行判斷,這時我們就能拼接自己定義的內容,而不是用戶輸入的內容。這樣即使我們拼接了語句也不會被注入,所以這是一個使用 ${ } 時非常重要的小技巧


優勢與劣勢

優勢 劣勢
${ } 字符串拼接 可以隨意拼接 有sql注入的風險
#{ } 占位符 規避sql注入風險 要和列相關的位置才可以使用


總結

        當我們想要去取值時,能用 #{ }就盡量用 #{ },什么時候不能用 #{ }呢?如果這個位置不是為某個列做值的相關,而是要在某些sql片段上進行動態填充,那我們必須用 ${ }來取值。


資料參考

https://www.bilibili.com/video/BV1gC4y1p7z2?p=845


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM