"#{}"是将传入的值按照字符串的形式进行处

     SELECT
             *
        FROM
            `t_information`
        where
             project_id=#{projectId}
             AND is_delete=0
        order by sets

MyBaits会首先对其进行预编译,将#{user_ids}替换成?占位符,然后在执行时替换成实际传入的user_id值,**并在两边加上单引号,以字符串方式处理。下面是MyBatis执行日志:

9:30:20.247 [main] DEBUG william.mybatis.quickstart.mapper.UserMapper.selectInformation- ==>  Preparing:SELECT *FROM `t_information` where project_id=? AND is_delete=0
order by sets
9:30:20.285 [main] DEBUG william.mybatis.quickstart.mapper.UserMapper.selectInformation- ==> Parameters: 1(Long)

"${}"是做简单的字符串替换,即将传入的值直接拼接到SQL语句中,且不会自动加单引号。将上面的SQL语句改为:

     SELECT
             *
        FROM
            `t_information`
        where
             project_id=${projectId}
             AND is_delete=0
        order by sets

再观察MyBatis的执行日志:

9:30:20.247 [main] DEBUG william.mybatis.quickstart.mapper.UserMapper.selectInformation- ==>  Preparing:SELECT *FROM `t_information` where project_id= 1 AND is_delete=0
order by sets
9:30:20.285 [main] DEBUG william.mybatis.quickstart.mapper.UserMapper.selectInformation- ==> Parameters: 

可以看到,参数是直接替换的,且没有单引号处理,这样就有SQL注入的风险。

  预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。预编译完成之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。