mybatis编写SQL语句的时候,经常需要用到变量替换值,那么用来替换变量值的操作经常用到$和#这两个符号,同样在一些Java面试中也经常被问到它们的区别。那么它们在使用上面有什么区别呢?
一、${}与#{}的区别
1、符号类型
(1)#{}:参数占位符,即预编译,#作用相当于变量值替换
(2)${} :字符串替换符,即SQL拼接,$作用相等于是字符串拼接
2、防注入问题
(1)#{}:很大程度上能防止sql 注入
(2)${}:不能防止sql 注入
3、参数解析
#会把传入的数据都当成一个字符串来处理,会在传入的数据上面加一个单引号来处理。
而$则是把传入的数据直接显示在sql语句中,不会添加单引号。
(1)#{}:将传入的数据都当成一个字符串,会对传入的变量自动加一个单引号。如:username = #{username },如果传入的值是zhangsan,那么解析成sql时的值为username = ‘zhangsan’,如果传入的值是数值类型,比如输入11,则解析成的sql为username = ‘11’。
(2)${}:将传入的参数直接显示生成在sql中,且不加任何引号。如:username = ${username},如果传入的值是111,那么解析成sql时的值为username = 111 ,不会报错,但如果传入的值是字符串类型,比如输入zhangsan,则解析成的sql为username = zhangsan,执行会报错,所以sql语句必须写出这样 username='${username}'。
4、#和$使用场景不同
(1)在sql语句中,如果要接收传递过来的变量的值的话,必须使用#。可以防止sql注入,并且在多次执行sql语句时可以提高效率。
(2)$只是简单的字符串拼接而已,所以要特别小心sql注入问题。对于sql语句中非变量部分,那就可以使用$,比如$方式一般用于传入数据库对象(如传入表名)。
例如:
select * from ${tableName},$ 对于不同的表执行统一的查询操作时,就可以使用$来完成。
(3)如果在sql语句中能同时使用#和$的时候,最好使用#。
5、sql执行过程
可参考“二”部分的案例
(1)#{}:编译好SQL后语句再去取值
(2)${}:取值以后再去编译SQL语句
二、SQL解析
1、流程
(1)#{}:动态解析 -> 预编译 -> 执行
(2)${}:动态解析 -> 编译 -> 执行
2、案例
根据用户名name查询用户表user数据,如果 name 的值为 zhangsan
(1)SQL编写
#{}
select * from user where name = #{name};
${}
select * from user where name = ${name};
(2)(预)编译中的处理
#{}:在预处理时,会把参数用一个占位符" " 代替,变成以下SQL
select * from user where name = ?;
${}:只是简单的字符串替换,在动态解析时变成以下SQL
select * from user where name = zhangsan;
但是这样就会报sql错误,因为name是字符串类型,而name=zhangsan,不是字符串类型,因改为:
select * from user where name = '${name}';
改完后,最后的解析结果是一样的,都是
select * from user where name = 'zhangsan';