mybatis中#與$的區別


MyBatis中使用parameterType向SQL語句傳參,parameterType支持的類型可以是基本類型int,String,HashMap和java自定義類型。

在SQL中引用這些參數的時候,可以使用兩種方式:

#{parameterName}

${parameterName}

首先,我們說一下這兩種引用參數時的區別,使用#{parameterName}引用參數的時候,Mybatis會把這個參數認為是一個字符串,並自動加上'',例如傳入參數是“Smith”,那么在下面SQL中:

Select * from emp where name = #{employeeName}

使用的時候就會轉換為:

Select * from emp where name = 'Smith'; 

同時使用${parameterName}的時候在下面SQL中

Select * from emp where name = ${employeeName}

就會直接轉換為:

Select * from emp where name = Smith

簡單說#{}是經過預編譯的,是安全的

${}是未經過預編譯的,僅僅是取變量的值,是非安全的,存在SQL注入

#{} 這種取值是編譯好SQL語句再取值
${} 這種是取值以后再去編譯SQL語句

下面我們用一個實際的例子看看分別使用和是否可以防止SQL注入。

首先是使用#{}:

<!-- 使用#{} -->
  <select id="selectUser" parameterType="String" 
    resultType="com.mybatis.po.MyUser">
    select * from user where account = #{account} and password = #{password}
  </select>

分別測試正常傳參和拼接傳參:

// 使用#{} 正常傳參
    Map<String, Object> parameter = new HashMap<>();
    parameter.put("account", );
    parameter.put("password", password);
    MyUser mu = ss.selectOne("com.mybatis.mapper.UserMapper.selectUser", parameter);
    System.out.println("返回結果:" + mu);
    
    // 使用#{} 拼接傳參
    Map<String, Object> parameter_1 = new HashMap<>();
    parameter_1.put("account", "201301001");
    parameter_1.put("password", "111111" + "or account = 'admin' ");
    MyUser mu_1 = ss.selectOne("com.mybatis.mapper.UserMapper.selectUser", parameter_1);
    System.out.println("返回結果:" + mu_1);

結果如下:

img

DEBUG [http-nio-8080-exec-5] - ==>  Preparing: select * from user where account = ? and password = ? 
DEBUG [http-nio-8080-exec-5] - ==> Parameters: 201301001(String), 111111(String)
DEBUG [http-nio-8080-exec-5] - <==      Total: 1
返回結果:MyUser [id=17, account=201301001, password=111111, name=蒙奇D路飛]
DEBUG [http-nio-8080-exec-5] - ==>  Preparing: select * from user where account = ? and password = ? 
DEBUG [http-nio-8080-exec-5] - ==> Parameters: 201301001(String), 111111 or account = 'admin' (String)
DEBUG [http-nio-8080-exec-5] - <==      Total: 0
返回結果:null

很明顯,使用#{}的時候,即使傳入了惡意參數,#{}只會將其作為一個占位符的參數,如上面這個例子:

DEBUG [http-nio-8080-exec-5] - ==>  Preparing: select * from user where account = ? and password = ? 
DEBUG [http-nio-8080-exec-5] - ==> Parameters: 201301001(String), 111111 or account = 'admin' (String)
DEBUG [http-nio-8080-exec-5] - <==      Total: 0
轉換為實際的SQL語句:select * from user where account = '201301001' and password = '111111 or account = 'admin'' 

現在是使用${}

<!-- 使用${} -->
  <select id="selectUser2" parameterType="String" 
    resultType="com.mybatis.po.MyUser">
    select * from user where account = ${account} and password = ${password}
  </select>

分別測試正常傳參和拼接傳參:

 // 使用${} 正常傳參
     Map<String, Object> parameter = new HashMap<>();
     parameter.put("account", "201301001");
     parameter.put("password", "111111");
     MyUser mu = ss.selectOne("com.mybatis.mapper.UserMapper.selectUser2",parameter);
     System.out.println("返回結果:" + mu);

    // 使用${} 拼接傳參
    Map<String, Object> parameter2 = new HashMap<>();
    parameter2.put("account", "201301001");
    parameter2.put("password", "111111" + " or account = 'admin' ");
    MyUser mu2 = ss.selectOne("com.mybatis.mapper.UserMapper.selectUser2", parameter2);
    System.out.println("返回結果:" + mu2);

結果如下:

img

DEBUG [http-nio-8080-exec-18] - ==>  Preparing: select * from user where account = 201301001 and password = 111111 
DEBUG [http-nio-8080-exec-18] - ==> Parameters: 
DEBUG [http-nio-8080-exec-18] - <==      Total: 1
返回結果:MyUser [id=17, account=201301001, password=111111, name=蒙奇D路飛]
DEBUG [http-nio-8080-exec-18] - ==>  Preparing: select * from user where account = 201301001 and password = 111111 or account = 'admin' 
DEBUG [http-nio-8080-exec-18] - ==> Parameters: 
DEBUG [http-nio-8080-exec-18] - <==      Total: 2
返回結果:[MyUser [id=1, account=admin, password=111111, name=管理員], MyUser [id=17, account=201301001, password=111111, name=蒙奇D路飛]]

很明顯,使用${}將參數拼接后在編譯成SQL語句,不能防止SQL注入,查詢出了有關account=admin的額外信息,這是很危險的。

Mybatis中的#{}用於傳遞查詢的參數,用於從dao層傳遞一個string參數過來(也可以是其他參數),select * from 表名 order by age=#{age}

Mybatis會把這個參數轉換成一個字符串。select * from 表名 order by age="age" 相當於jdbc中的預編譯,安全。

而${}一般用於order by的后面,Mybatis不會對這個參數進行任何的處理,直接生成了sql語句。例:傳入一個年齡age的參數,select * from 表名 order by ${age}

Mybatis生成的語句為 select * from 表名 order by age Mybatis不會對$傳遞的參數做任何處理,相當於jdbc中的另外一種編譯方式。

一般我們使用#{},不使用${},原因:

會引起sql注入,${}會直接參與sql編譯。會影響sql語句的預編譯。
引自:

https://www.2cto.com/database/201707/654691.html
https://cloud.tencent.com/developer/article/1455878


免責聲明!

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



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