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);
結果如下:
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);
結果如下:
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