1、#{}是预编译处理,$ {}是字符串替换
(1)#{} 表示一个占位符,采用preparedStatement给占位符设置值,自动进行java类型和jdbc类型转换,进行预编译处理,#{}可以有效防止sql注入(预编译是提前对SQL语句进行编译,而其后注入的参数将不会再进行编译)
(2)${} 表示字符串替换,通过${}可以将parameterType或实体 传入的内容拼接在sql中且不进行jdbc类型转换
(3)举例说明二者区别,现在有如下SQL:
select count(1) from user where user_name = #{userName} and password = #{password}
使用#{}时,会进行jdbc类型转换,根据属性 自动加上单引号
select count(1) from user where user_name = 'admin' and password = '123456';
而${}不会进行jdbc类型转换,只是简单的替换, 显然有语法错误,但是可以利用其进行sql注入
select count(1) from user where user_name = admin and password = 123456;
2、SQL注入举例离说明
SQL注入就是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库执行一些恶意的操作。比如说,在登录过程中,利用上面的语句到数据库中查找用户名/密码是否存在,如果存在就登录成功,如果不存在就登录失败。
若使用${},恶意用户在表单中的用户名文本框中输入的是'admin',密码框中输入的是 ' ' or 1 = 1 加了一引号和一个恒成立的条件,那么,传到数据库中的sql就是:
select count(1) from user where user_name = 'admin' and user_password = ' ' or 1=1
登录成功,该恶意用户是可以登录系统的! 这就是SQL注入,恶意攻击
而如果使用#{}是不会出现这种情况的,#{}默认会给输入的值加上引号,密码错误,登录失败
select count(1) from user where user_name = ''admin'' and user_password ='' ' or 1=1'
3、既然有了#{}为什么还需要${}
#{}并不适用一些其他场景,比如要根据参数名动态排序,需要传入的参数是字段名,使用#{} 被解析成order by 'age' ,显然达不到排序目的。而此时就用到了${}进行字符串替换操作,即sql解析成 order by age