mybatis中的#{}和${}区别仅仅是加不加单引号吗?

724 阅读2分钟
  • #{}:预编译。
  • ${}:sql拼接。

在网上看了很多文章,很多对于这个的解释就是,一个自动加单引号,一个需要手动加单引号。 这种说法其实是错的,想一下如果传入的是Integer类型的参数,那么#{}还会去添加单引号吗,如果是日期类型呢?还会添加单引号吗? 所以这种说法就是错的!

我们要弄清#{}和${}的区别 我们就要首先知道什么是preparestatement和statement,什么是预编译?为什么预编译不会导致sql注入。

preparestatement和statement

#{}底层是preparestatement,${}底层是statement。使用过jdbc操作数据库的都应该知道,prepare statement是预编译对象,通过?来进行参数的占位。而statement 是直接拼接sql语句的。这里就会引出为什么预编译对象不会造成sql注入的问题。至于sql注入问题 不清楚的去搜搜。

什么是预编译?

在我们创建prepare statement的时候 我们就会传入sql语句如果带有参数 我们会用?进行占位,此时该sql语句就会率先交给数据库进行编译解析,把这个sql语句 整体结构固定。当我们通过set方法设置参数完后,再执行execute或者executquery方法,此时数据库会根据传入的参数和问好进行替换,并执行最开始编译好的sql语句。 这就是所谓的预编译。而statement是直接将一个完整的sql直接传入数据库进行编译执行。

为什么预编译能防止sql注入?

statement的中是直接将一条完整的sql传递给数据库,一次性的编译并执行。所以在客户端我们对sql进行拼接时,很有可能会因为参数而把原始的sql结构改变。数据库再执行该SQL的时候,就不是我们期望的那样。这也是为什么statement会有sql注入问题。 但是预编译就防止了这样的问题,预编译是先把sql不包含参数交给数据库进行整体的编译,后面我们传入的参数并不会去改变原先sql的整体结构。那问题也就来了 是怎么保证参数不会对sql造成影响呢? 这时我们就需要知道,预编译对象在设置参数时,他是知道参数的类型的,根据参数类型,对应mysql中的数据类型进行修改。比如传入的参数是String,那么预编译对象就知道String 对应的是varchar。此时也会自动加单引号,如果是Integer,那么就会对饮mysql中的int,此时就不会加单引号,日期Date对应datetime等等。

我们可以清楚看到,参数类型明确知道是Integer。此时就不会加单引号。

如果再有人说这俩的区别是自动加单引号,和手动加单引号。不要和他争论,大嘴巴子伺候。和自动加不加单引号没关系