默认状况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,而且安全的设置PreparedStatement参数,这个过程当中MyBatis会进行必要的安全检查和转义。sql
#至关于对数据 加上 双引号,$至关于直接显示数据数据库
示例1:
执行SQL:select * from emp where name = #{employeeName}
参数:employeeName=>Smith
解析后执行的SQL:select * from emp where name = ?安全
示例2:框架
执行SQL:select * from emp where name = ${employeeName}
参数:employeeName传入值为:Smith
解析后执行的SQL:Select * from emp where name =Smith函数
综上所述、${}方式会引起SQL注入的问题、同时也会影响SQL语句的预编译,因此从安全性和性能的角度出发,能使用#{}的状况下就不要使用${}性能
Q:可是${}在什么状况下使用呢?spa
A:有时候可能须要直接插入一个不作任何修改的字符串到SQL语句中。这时候应该使用${}语法。对象
好比,动态SQL中的字段名,如:ORDER BY ${columnName}blog
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样作是不安全的。这会致使潜在的SQL注入攻击,所以你不该该容许用户输入这些字段,或者一般自行转义并检查。字符串
MyBatis框架做为一款半自动化的持久层框架,其SQL语句都要咱们本身手动编写,这个时候固然须要防止SQL注入。其实,MyBatis的SQL是一个具备“输入+输出”的功能,相似于函数的结构,以下:
<select id="getBlogById" resultType="Blog" parameterType=”int”> SELECT id,title,author,content FROM blog WHERE id=#{id} </select>
这里,parameterType表示了输入的参数类型,resultType表示了输出的参数类型。回应上文,若是咱们想防止SQL注入,理所固然地要在输入参数上下功夫。上面代码中黄色高亮即输入参数在SQL中拼接的部分,传入参数后,打印出执行的SQL语句,会看到SQL是这样的:
SELECT id,title,author,content FROM blog WHERE id = ?
无论输入什么参数,打印出的SQL都是这样的。这是由于MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就能够了。由于SQL注入只能对编译过程起做用,因此这样的方式就很好地避免了SQL注入的问题。
【底层实现原理】MyBatis是如何作到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起做用,PreparedStatement是咱们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不只能提升安全性,并且在屡次执行同一个SQL时,可以提升效率。缘由是SQL已编译好,再次执行时无需再编译。
在MyBatis中,${xxx}这样格式的参数会直接参与SQL编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用${xxx}这样的参数格式。因此,这样的参数须要咱们在代码中手工进行处理来防止注入。
【结论】
在编写MyBatis的映射语句时,尽可能采用#{xxx}这样的格式。若不得不使用${xxx}这样的参数,要手工地作好过滤工做,来防止SQL注入攻击。
#{}:至关于JDBC中的PreparedStatement
${}:是输出变量的值
简单说,#{}是通过预编译的,是安全的;${}是未通过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。
若是咱们order by语句后用了${},那么不作任何处理的时候是存在SQL注入危险的。你说怎么防止,那我只能悲惨的告诉你,你得手动处理过滤一下输入的内容。如判断一下输入的参数的长度是否正常(注入语句通常很长)
原理介绍:
myBatis 对于#{} 在boundSql 的时候,会将sql 语句解析成为?;对于${} 则原本的值进行替换。
对于 select * from emp where name = #{employeeName},myBatis 会解析sql为:select * from emp where name = #{employeeName},而后进行prepareStatment 预编译处理。
对于 select * from emp where name = ${employeeName},myBatis 会解析sql为:select * from emp where name = 'employeeName',而后进行prepareStatment 预编译处理。
myBatis 其实底层防止sql注入,使用的是prepareStatment语句。表现为#{employeeName}和${employeeName}的两种参数注入方法。