面试-3.MyBatis中#与$的区别,PrepareStatement

MyBatis中#与$的区别

0.c 防止sql 注入

举个例子:

	String sql = "select id from t_user where name =?";  

	PreparedStatement prep = conn.prepareStatement(sql);  
	prep.setString(1, name);  
    ResultSet rst = prep.executeQuery();  
  • 使用PrepareStatement时,SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析和编译,对应的执行计划也会缓存下来,之后数据库就会以参数化的形式进行查询。当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如上图中 or ‘1=1’,它也会作为一个字段的值来处理,而不会作为一个SQL指令。从根本上讲,其实就是data VS. code的问题,确保data永远是data,不会是可执行的code,就杜绝了SQL注入这种问题。

1.MyBatis

MyBatis中使用parameterType向SQL语句传参,parameterType支持的类型可以是基本类型int,String,HashMap和java自定义类型。

在SQL中引用这些参数的时候,可以使用两种方式:

  • #{parameterName}

  • ${parameterName}

mybatis对这两种参数的处理分为两个阶段,

     首先为构建sqlsessionFactory的时候,这个时候的处理为,如果sql中含有${}则该条sql不做处理,如果sql中全是#{}则替换为 ? 。

     然后是sqlSession执行sql阶段,该阶段首先会将${value} 原封不动的替换为 value传过来的值,然后在将sql中的#{} 替换为 ? 。

2.总结

  • ${} 会将传入的参数完全拼接到sql语句中,也就是相当于一个拼接符号。比如说 : String sql = select * from user where id=${value}
          最后的处理方式就相当于 MyBatis 会将 ${value} 完全替换为参数 value 的值。 相当replace("${value}", value)的过程。实际上mybatis 是先将sql转成char数组,然后截取 "KaTeX parse error: Expected '}', got 'EOF' at end of input: …的部分放入到容器,替换 以"{"开头 以 "}"结尾的内容。所以说它的作用相当于拼接符号。拼接后直接作为sql语句的一部分,所以如 果参数是可执行代码,sql是会直接执行的。这就是为什么它会导致sql注入。

  • #{} 是一个占位符, mybatis最后会将这个占位符,替换成?,最后才进行prepareStatement的相应位置的?的替换,也就是 state.setString(序号,值),setInt(序号,值)等。

使用#{}传递参数,被JDBC解析为PreparedStatement预编译语句,变量内容被当做一个整体变量,比如字符串,整形等。使用${}传递参数,纯粹是字符串替换,中间出现SQL语句,也会被正常执行。所以,在Mybatis中使用使用$传递参数时,需要考虑sql注入的问题。

Tips:
      ${}方式一般用于传入数据库对象,例如传入表名、字段名。
      排序时使用order by 动态参数时需要注意,用${}而不是 #{}。

你可能感兴趣的:(面试,Mybatis)