# 和 $ 的区别②

上节博客说了使用 # 的时候,如果参数为 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());
    }

使用 $ 才能正常运行 

# 和 $ 的区别②_第1张图片

还有一种情况不能使用 # ,那就是模糊查询 

进行模糊查询的时候也只能用 $

@Select("select * from userinfo where username like'%${username}%'")
    List selectUserByLike(String username);
@Test
    void selectUserByLike() {
        log.info(userInfoMapper.selectUserByLike("java").toString());
    }

# 和 $ 的区别②_第2张图片

 有的人可能会觉得那我们在排序和模糊查询的时候使用 $ ,其他有需要引号的情况只要拼接上引号也可以使用 $ ,那我们就不用 # 了吗?

这是不可以滴,因为 $ 存在 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());
    }

 很明显把所有数据都给查出来了,这是错误的

# 和 $ 的区别②_第3张图片

接下来我们试试 #

@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 的数据,所以啥也没查出来,没问题

# 和 $ 的区别②_第4张图片

同样是加引号,为什么# 不会发生SQL注入的问题?

SQL 执行的过程为 : 1.语法解析 2.SQL优化 3.SQL编译

然后呢, # 是预编译SQL,将编译一次之后的SQL语句缓存起来了,后面再次执行的时候,省去了解析优化等过程,提高了效率,预编译SQL也可以说是一个模版,往里套数据就行.

比如 select * from userinfo where username = '_____';

预编译SQL就只给你留下了这个位置,你填进去之后就只能是 username 的参数

而即时SQL就是你传的参数是什么就现场进行拼接,拼出来之后再对这条语句进行上面三个过程

所以这就是为什么 # 不会发生 SQL 注入的原因

但是在进行排序的时候,只能使用 $ 的时候,发生SQL注入怎么办呢?

可以进行参数校验,只要不是 asc 和 desc 就不接收这个请求

模糊查询的时候使用Mysql的内置函数

# 和 $ 的区别②_第5张图片

@Select("select * from userinfo where username like CONCAT('%',#{username},'%')")
    List selectUserByLike(String username);
 @Test
    void selectUserByLike() {
        log.info(userInfoMapper.selectUserByLike("java").toString());
    }

 # 和 $ 的区别②_第6张图片

总结 # 和 $ 的区别 : 

其中之一就是预 编译SQL 和 即时SQL 的区别

    1)预编译SQL 的性能更高

    2)预编译SQL 不存在 SQL注入 问题

排序时不能使用 #

表名,字段名等作为参数时也不能使用 #

模糊查询时,如果使用 # 就需要搭配 Mysql 的内置函数 concat

实际开发中尽量使用 # ,然后使用 $ 的时候一定要考虑到 SQL 注入的问题

你可能感兴趣的:(数据库,服务器,linux)