面试题:MyBatis中 #{} 跟 ${} 的区别

前置知识

SQL注入:后端并未对前端传来的参数进行严格的校验,同时后端存在将前端传来的参数使用字符串或者直接将参数拼接到SQL语句中,导致后端的SQL语句被篡改并且能成功执行

四大SQL注入原理

  • 恶意拼接查询--查询、插入、更新和删除数据,且使用分号来分隔不同的命令
    • 原SQL语句 select * from student where id = ${id}
    • 恶意拼接后的SQL select * from student where id = '1'; delete from student;  多出了一条删除语句,将删除全表数据
  • 使用注释方式执行非法命令--在MySQL中,注释的符号为 --
    • 原SQL语句 select * from student where age = ${age} and sex = '1'   
    • 非法命令注入的SQL select * from student where age = 11 or 22 and sleep(500) -- and sex = '1'   注释将后面的查询条件去掉了,同时SLEEP(500) 将导致 SQL 语句一直运行,耗尽系统资源
  • 接收非法的参数--SQL中传入的字符串参数是用单引号引起来的,如果字符串本身包含单引号而没有被处理,那么可能会篡改原本 SQL 语句的作用
    • 原SQL语句 select * from student where name = ${name} and sex = '1' 
    • 接收非法参数的SQL:select * from student where name = 'wen'' and sex = '1'  此语句数据后台会执行报错
  • 添加额外的条件--SQL中添加额外条件,以此来改变执行行为。条件一般为真值表达式
    • 原SQL语句: select * from student where name = ${name}
    • 添加额外条件的SQL:select * from student where name = 'wen' or 1=1 此语句将查询所有数据而非name为wen的数据       

SQL预编译语句:某一条SQL能被反复执行,或者每次执行时只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同),此时可以将此类SQL语句中的值用占位符替代

SQL预编译优势

  • 一次编译、多次运行,省去了词法语义解析、语句优化、制定执行计划等过程
  • 防止 SQL 注入

MyBatis中 #{} 跟 ${} 的区别

在MyBatis的Mapper映射文件中,有两种动态的引用形参变量的方式进行取值:#{} 和 ${}

<select id="getAllStudent" parameterType="string" resultType="com.wen.server.pojo.Student">
        SELECT * FROM student WHERE name like concat('%',concat(#{name},'%'))
</select>

 

<select id="getAllStudent" parameterType="string" resultType="com.wen.server.pojo.Student">
        SELECT * FROM student WHERE name like concat('%',concat('${name}','%'))
</select>

#{}方式

使用 #{} 可实现预编译功能,SQL中的参数解析为JDBC的预编译语句中参数标记符,将参数部分使用占位符  ?  代替,同时对传入的参数值经PreparedStatement方法的强制类型检查和安全检查操作,最后作为一个合法的字符串传入

数据类型检查:若检测到为数值类型,就不加引号,即 ? ;若检测到位字符串类型,就加上引号,即 '?'

安全检查:若变量的值带有引号,会对引号进行转义处理,可以防止SQL注入

预编译步骤如下

  1. 将参数部分使用占位符  ?  代替
    1. SELECT * FROM student WHERE name like concat('%',concat(?,'%'))
  2. 强制类型检查和安全检查操作,最后作为一个合法的字符串传入
    1.  预编译参数传入SELECT * FROM student WHERE name like concat('%',concat('wen','%'))
    2. SQL执行 SELECT * FROM student WHERE name like '%wen%'

使用场景:动态拼接SQL,多数用在模糊查询、where子句中多个条件的查询、pojo对象等。例如 SELECT * FROM student WHERE name like concat('%',concat(#{name},'%'))

${}方式

 使用 ${} 方式是做字符串的替换,在动态SQL解析阶段会将变量直接替换为参数的值。使用该语法会存在SQL注入问题

预编译步骤如下

  1.  在SQL解析阶段就将该变量的替换成了变量的值  SELECT * FROM student WHERE name like concat('%',concat('wen','%'))  
  2. SQL执行 SELECT * FROM student WHERE name like '%wen%'

 使用场景:需要动态指定查询字段名、表名、order by指定排序字段名的动态SQL,并且需要注意什么时候需要带单引号,什么时候不需要(表名、字段名、数值不需要单引号)。例如 SELECT ${columnName} FROM ${tableName} WHERE name like concat('%',concat(#{name},'%'))

 

posted @ 2022-07-16 15:11  伊文小哥  阅读(58)  评论(0编辑  收藏  举报