目录
一,#{} 和 ${} 的使用
1.1 Integer 类型参数
1.2 String 类型的参数
二,#{} 和 ${} 的区别
2.1 性能区别
2.2 SQL注入问题
2.3 ${ } 的使用场景
排序
模糊查询 - like
一,#{} 和 ${} 的使用
1.1 Integer 类型参数
@Select("select * from userInfo where id = #{id}")public UserInfo queryUserInfoById(Integer id);@Select("select * from userInfo where id = ${id}")public UserInfo queryUserInfoById(Integer id);
可以发现这两种写法的SQL语句是不同的,对于${}来说,我们出入的参数是直接拼接在SQL语句中了,这对于Integer参数来说不会造成什么影响。
1.2 String 类型的参数
@Select("select * from userInfo where username = #{name}")UserInfo queryUserInfoByName(String name);@Select("select * from userInfo where username = ${name}")UserInfo queryUserInfoByName(String name);
对于${}来说,它仅仅只是把我们传入的字符串拼接到SQL语句中,但是对于SQL语句来说,如果我们要输入一个字符串,它必须要有引号( " " 或 ' ' ),所以我们不能直接使用${}来传递一个字符串参数,我们必须要自己在@Select注解中主动添加引号,如下:
@Select("select * from userInfo where username = '${name}'")UserInfo queryUserInfoByName(String name);
从上述两个例子可以看出:
- #{ } 使用的是预编译SQL,通过 ?占位的方式,提前堆SQL进行编译,然后用参数替换掉 ?,#{ } 会根据参数类型,自动拼接引号 ' '
- ${ } 使用的是即时SQL,它会直接进行字符替换,然后一起对SQL进行编译,如果参数为String类型时,必须要自己加上引号
二,#{} 和 ${} 的区别
#{} 和 ${} 的区别就是 预编译SQL 和 即时SQL 的区别,要想弄明白 预编译SQL 和 即时SQL 的区别,需要先了解一下一条SQL语句发送给服务器的大致流程:
- 解析语法和语义,校验SQL语句是否正确
- 优化SQL语句,制定执行计划
- 执行并返回结果
2.1 性能区别
#{ } 性能更高,${ } 性能较低:
对于Java接口中定义的SQL语句来说,只有参数会不断的变化,其他都是固定的,而预编译SQL恰好可以缓存 1,2 流程,也就是只需要替换参数,可以跳过解析,编译和优化,直接执行SQL语句;而即使SQL必须要经历解析,编译和优化才能执行
2.2 SQL注入问题
SQL注入是指通过操作传参来修改SQL语句,以达到攻击服务器的目的。对于${ }来说,因为它的SQL语句是拼接而成的,所以在用户输入参数时,可以添加一些恒等式来到达改变SQL运行结果的目的,比如我们可以传入这样一个参数 ' or 1 = '1 :
@Select("select * from userInfo where username = '${name}'")List<UserInfo> queryUserInfoByName(String name);
这样我们根本不需要知道username,就可以直接把所有人的信息都查找出来,如果不对输入的参数进行校验 / 限制,对于一些登录场景,我们也可以通过填写 ' or 1 = '1来完成登录操作。我们甚至可以通过该方式完成删库删表等危险操作。
所以#{ }的安全性更高,而${ }则有SQL注入的风险,安全性较低。
2.3 ${ } 的使用场景
排序
@Select("select * from userInfo order by id #{sort}")List<UserInfo> queryAll(String sort);@Select("select * from userInfo order by id ${sort}")List<UserInfo> queryAll(String sort);
这时我们需要传递的只是字符串本身,不需要引号,所以只能由${ }来实现。
模糊查询 - like
@Select("select * from userInfo where username like '%${name}%'")List<UserInfo> queryUserInfoByName(String name);
当然这么写还是会出现SQL注入问题,所以我们可以使用concat函数来避免使用${ },代码如下:
@Select("select * from userInfo where username like concat('%', #{name}, '%')")List<UserInfo> queryUserInfoByName(String name);