MyBatis--#{}和${}
#{}:预编译SQL。
${}: 即时SQL。
当用户发送一条SQL语句给服务器后,大致流程如下:
1.解析SQL语句的语法和语义,校验SQL语句是否正确。
2.优化SQL语句,制定执行计划。
3.编译SQL语句。
4.执行SQL并返回结果。
一个SQL如果是上述流程,我们称之为即时SQL。
#{}的优点:
1.性能更高
在大多数情况下,某一天SQL会被反复执行,或者每次执行只是个别的值不同,如果每次都要将上述几步全部走完,效率就会比较低。
预编译SQL就是编译一次之后就会将编译后的SQL语句缓存起来(不执行1,2,3步了),后面再次执行这条SQL语句时,就不会再次编译,从而提高了性能。
*2.更安全(防止SQL注入)
这是#{}最主要的一个优点。
SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。
关于SQL注入,首先需要明白的是${}是将参数直接拼接到SQL语句后的,也就是没有“”,而#{}是在执行 SQL 时,MyBatis 会把#{}
替换成?
,再使用预编译语句(PreparedStatement)给?
赋值。这样能有效防止 SQL 注入攻击,因为参数会被当作一个整体来处理,会自动对特殊字符进行转义。
例如:使用#{}时
<select id="queryUserByusername" resultType="com.example.mybatisxml.Model.UserInfo">
select id,age,username,password from user_info by #{username}
</select>
实际上执行的是:
SELECT * FROM user——info WHERE username = ?
然后再将输入的参数赋值给?
使用${}时:
<select id="queryUserByusername" resultType="com.example.mybatisxml.Model.UserInfo">
select id,age,username,password from user_info where username = ${username}
</select>
输入参数“zhangsan”,运行结果报错,其中一句提示是这样的:
可以看出${}是将zhangsan直接拼接到了 = 的后面,这也意味着可以通过写“‘’;drop database****;”这类语句来攻击服务器,因为服务器会将后面的drop database ****;识别为一句SQL语句。
${}应用的场景:
1.排序功能
对于SQL语句:select id, username from user_info order by id #{sort}.
List<UserInfo> queryUserBySort(String sort)
如果我们传入参数“asc”,IDEA就会报错,因为#{sort}会给asc自动添加引号,从而导致SQL错误。(因为参数类型为String,会自动加上引号)。
除此之外,如果将表名作为参数时,也会加上引号。
2.like查询
如果使用#{}:
<select id="queryUserlike" resultType="com.example.mybatisxml.Model.UserInfo">
select id,age,username,password from user_info where username like '%#{username}%'
</select>
List<UserInfo> queryUserlike(String username);
会报个这样的错误:
但是使用${}的话,则正常运行:
但是MySql内置了一个函数concat()来处理:
<select id="queryUserlike2" resultType="com.example.mybatisxml.Model.UserInfo">
select id,age,username,password from user_info where username like concat('%', #{username},'%')
</select>
List<UserInfo> queryUserlike2(String username);
运行结果:
总结来说,当参数类型为String且不需要‘’的时候,使用${},不过需要注意SQL注入问题。