MyBatis 在对实体类配置映射文件中时 传递参数可以有 #{ } 和${ }两种 那么这两种到底有什么区别呢,
1、#{ }形式:
select * from smbms_user where 1=1 and userName like concat ('%',#{userName},'%')
编译结果:
DEBUG - ==> Preparing: select * from smbms_user where 1=1 and userName like concat ('%',?,'%')
DEBUG - ==> Parameters: 赵(String)
2、${ }形式:
select * from smbms_user where 1=1 and userName like ('%${userName}%')
编译结果:
DEBUG - ==> Preparing: select * from smbms_user where 1=1 and userName like ('%赵%')
DEBUG - ==> Parameters:
来看这两个语句的编译结果
#{ }形式传入参数 编译后参数时一个一?为占位符的语句,然后在赋值,替换占位符。
${ }形式传入参数,编译时就已经吧值放到了语句的参数位置,然后执行语句。
由此我们可以看出,#{ }形式的传参是安全的,可以有效的避免SQL注入。
${ }形式的传参是不安全的,容易被SQL注入。
大家还会看到一个问题,这两个映射文件的SQL语句不只是这点不同吧 ?
没错 还有这里 concat 这个关键字
MySQL中 concat函数用于将多个字符串连接成一个字符串
例如
select CONCAT('a','b','c')
运行结果是 abc
select CONCAT('a',b,'c')
运行则会报错
显然:上面的语句参入参数(赵)后的编译 是不同的,如果都用concat函数的话
select * from smbms_user where 1=1 and userName like concat ('%',#{userName},'%')
#{ } 编译形式 结果为
DEBUG - ==> Preparing: select * from smbms_user where 1=1 and userName like concat ('%',?,'%')
DEBUG - ==> Parameters: 赵(String)
MyBatis 的解释为:?为一个占位符,会被一个varchar类型的值替代,替代后的结果为
select * from smbms_user where 1=1 and userName like concat ('%','赵 ','%')
执行concat函数后为:
select * from smbms_user where 1=1 and userName like concat ('%赵%')
这样的语句在执行是没有问题的。
如果是这样呢??
select * from smbms_user where 1=1 and userName like concat ('%',${userName},'%')
${ }形式 编译结果为
DEBUG - ==> Preparing: select * from smbms_user where 1=1 and userName like concat ('%',赵,'%')
DEBUG - ==> Parameters:
直接把参数放到了入参的位置上,然后交给Mysql去解释,结果是这样的:
[SQL]select * from smbms_user where 1=1 and userName like concat ('%',赵,'%')
[Err] 1054 - Unknown column '赵' in 'where clause'
报错,原因是,不存在列‘赵’。 mysql 无法没有吧 ‘赵’ 当做 concat的参数, 而是当做列来处理,所以执行报错
。
因此,#{ } 形式传参 和${ }传参还是有差异的 尤其是当使用参数做模糊查询时。
有句话很经典 ,一切以运行结果为准。语句的解释权在jar里,我们可以通过执行后的结果,来看错误。
菜鸟的见解,欢迎交流