上节博客说了使用 # 的时候,如果参数为 String ,会自动加上单引号
但是当参数为String 类型的时候,也有不需要加单引号的情况,这时候用 # 那就会出问题
比如根据 升序(asc) 或者 降序(desc) 查找的时候,加了单引号那就会报错
这个时候我们就只能使用 $
如果看不懂代码,就去看<
@Select("select * from userinfo order by id ${sort}")
List selectUserBySort(String sort);
@Test
void selectUserBySort() {
log.info(userInfoMapper.selectUserBySort("asc").toString());
}
使用 $ 才能正常运行
还有一种情况不能使用 # ,那就是模糊查询
进行模糊查询的时候也只能用 $
@Select("select * from userinfo where username like'%${username}%'")
List selectUserByLike(String username);
@Test
void selectUserByLike() {
log.info(userInfoMapper.selectUserByLike("java").toString());
}
有的人可能会觉得那我们在排序和模糊查询的时候使用 $ ,其他有需要引号的情况只要拼接上引号也可以使用 $ ,那我们就不用 # 了吗?
这是不可以滴,因为 $ 存在 SQL 注入的问题
打个比方 :
select * from userinfo where username = 'admin';
若是此时把admin换成 'or 1='1 ,那就变成了
select * from userinfo where username = ''or 1='1';
(这样前面两个引号就会形成一对,后面两个引号形成一对,这就导致where后面的搜索条件变成username=0或者1=1,因为1=1肯定恒成立,这样运行出来的结果就是搜索到全部数据,这与我们的想法背道而驰)
那这肯定就不对了呀,这就是 SQL 注入
# 就不会存在 SQL 注入的问题
我们用代码进行验证看看,先验证 $
@Select("select * from userInfo where username = '${username}'")
List selectByName(String username);
@Test
void selectByName() {
log.info(userInfoMapper.selectByName("'or 1='1").toString());
}
很明显把所有数据都给查出来了,这是错误的
接下来我们试试 #
@Select("select * from userInfo where username = #{username}")
List selectByName(String username);
@Test
void selectByName() {
log.info(userInfoMapper.selectByName("'or 1='1").toString());
}
因为没有名为 'or 1='1 的数据,所以啥也没查出来,没问题
同样是加引号,为什么# 不会发生SQL注入的问题?
SQL 执行的过程为 : 1.语法解析 2.SQL优化 3.SQL编译
然后呢, # 是预编译SQL,将编译一次之后的SQL语句缓存起来了,后面再次执行的时候,省去了解析优化等过程,提高了效率,预编译SQL也可以说是一个模版,往里套数据就行.
比如 select * from userinfo where username = '_____';
预编译SQL就只给你留下了这个位置,你填进去之后就只能是 username 的参数
而即时SQL就是你传的参数是什么就现场进行拼接,拼出来之后再对这条语句进行上面三个过程
所以这就是为什么 # 不会发生 SQL 注入的原因
但是在进行排序的时候,只能使用 $ 的时候,发生SQL注入怎么办呢?
可以进行参数校验,只要不是 asc 和 desc 就不接收这个请求
模糊查询的时候使用Mysql的内置函数
@Select("select * from userinfo where username like CONCAT('%',#{username},'%')")
List selectUserByLike(String username);
@Test
void selectUserByLike() {
log.info(userInfoMapper.selectUserByLike("java").toString());
}
总结 # 和 $ 的区别 :
其中之一就是预 编译SQL 和 即时SQL 的区别
1)预编译SQL 的性能更高
2)预编译SQL 不存在 SQL注入 问题
排序时不能使用 #
表名,字段名等作为参数时也不能使用 #
模糊查询时,如果使用 # 就需要搭配 Mysql 的内置函数 concat
实际开发中尽量使用 # ,然后使用 $ 的时候一定要考虑到 SQL 注入的问题