"#{}"是将传入的值按照字符串的形式进行处
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的结构产生影响,从而避免了潜在的安全风险。