我们开始先总结他们的差异,后面再使用代码展示差异
1.0.#{}和${}的差异
(1)${}可能存在sql注入的安全问题
(2)${}是即时sql(参数直接拼接),不能进行缓存;#{}是预编译sql(参数通过替换占位符的方式),可以缓存
(3)${}拼接字符串参数时不带引号,而#{}拼接参数会带上引号
(4)在不能自带引号的场景下,只能使用${};比如实现排序功能等
1.1.差异的原因
下面我们通过一段代码,就可以知道它们产生差异的原因了。
(1)参数是否拼接
分别使用不同符号的进行赋值
我们可以看到,当使用#{}的时候,参数位置使用的是一个占位符,而${}则是直接把参数拼接在上面了。这是它们两处不一样的地方。
(2)有无引号
下面我们将参数的类型从Integer换成String
测试结果:
发现直接使用$传参会报错,原因就是它没有自动加上双引号或者单引号;如果我们自己加上:
运行结果也就没有报错了
由此可见,${}就是可以自己是否带引号的,这点就是让它成为有sql注入的主要原因
(3)sql注入
在上面可以知道,${}可以自主选择带引号,因此,就可以进行sql拼接,也就存在被sql注入的风险。
比如下面的sql语句:
SELECT * from userinfo where username = ' ' or 1= '1'
//参数:' or 1='1
运行结果:
很明显sql执行成了,也就是说,确实是真真实实存在sql注入的风险。(但是一般都可以通过java代码来预防注入风险)
(4)即时sql和预编译sql
sql的执行流程:sql语法检验和解析、sql优化、sql执行
因为#{}的参数使用占位符,每次只需要替换占位符就可以,因此第一、二步可以缓存下来,每次只需要执行第三步即可,效率也就更快;因此称为:预编译sql。
而${}每次都是需要拼接参数,所以不能缓存,因此称为:即时sql
1.2.${}的作用
上面说的全是${}的缺点,那它还有用武之地吗?其实没有被淘汰,也就是还有作用的,作用场景也就是参数不能有引号的情况。
(1)对某个字段排序
对数据库中的数据进行排序,相信大家不陌生吧,我们还是先复习一下排序的sql语句
默认排升序:select * from 表名 order by 列名/表达式
排降序:select * from 表名 order by 列名/表达式 desc
如果我们需要排降序的话,就需要传参,也就是将desc作为参数,但是在sql语句中,desc是没有引号的,但是#{}对字符串传参时,会自动加上引号,进而会导致sql错误,所以只能使用${}
- 使用#{}时
结果已经很明显了。
- 使用${}
但是这样也会存在sql注入的安全问题,所以就需要将参数设置成枚举类型这样的可选类型。并且如果表名和字段名作为参数时也必须使用${},原因就是它们不能有引号
(2)模糊查询
模糊查询虽然不是使用${}和#{},但是也需要介绍一下原因。
复习一下模糊查询:
select * from userinfo where username like ' %min% '
%min%就是一个模糊的概念,两边是需要加上引号的。但是%min%是一个字符串,min就是我们需要的参数,不能有任何字符串。
- #{}
报错
- 使用${}
因为是${},所以依旧存在sql注入的风险,所以模糊查询不会使用${},而是使用内置函数
- 使用内置函数
@Select("select * from userinfo where username like concat('%',#{key},'%') ")
List<UserInfo> queryUserInfoBylike(String key);
以上就是本文的全部内容。