- 在我们开发过程中写mybatis的时候可能大多数人都使用的是#{} ,但是我们还有另外一个符号${},他们之间的区别是什么?
当我们在应用变量的时候默认使用#{},如下:
<select id=getUserById resultType="org.hyf.mybatis.model.User">
select * from user where id = #{id};
</select>
<select id=getUserById resultType="org.hyf.mybatis.model.User">
select * from user where id = ${id};
</select>
通过上面的例子好像并没有看出他们之间有什么区别
一、下面我们通过日志来看一下他们之间的区别:
添加日志依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
在resources目录下,添加log4j.properties
log4j.rootLogger=DEBUG,stdout
log4j.logger.org.mybatis=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
先看通过${}运行的日志:
从上面的日志中可以看出,${}是一个纯粹的string 替换,在动态sql解析阶段会进行变量替换
sql直接拼接就好了,Parameters为空
看#{}运行的日志
解析为一个JDBC的预编译语句的参数标记符
#{}是占位符的方式来解决参数传递问题,变量的替换是在DBMS中,而且替换会自动加单引号 ‘’
${}是参数拼接的问题,变量的替换是在动态SQL解析阶段,但是参数拼接可能会存在sql注入的
二、用法:
1.能用#{}的地方就用#{},因为${}存在sql注入非常的不安全,可能一条查询语句就能变成删表操作
例如:
select * from ${tableName} where name=#{name}
这个时候我们传递tableName 为 user;delete user; --
sql预编译之后变成:
select * from user; delete user; -- where name = ?;
2.表明作为变量的时候,必须使用${}
知道为什么吗? 这是由于如果我们使用#{}占位符传递的话会自动加上单引号‘’,但是${}不会自动加单引号
select * from #{tableName} where name = #{name};
预编译之后变成
select * from ? where name = ?;
假设我们传入的tableName=user name="zhangsan"
select * from 'User' where name='zhangsan';
上述sql语句是错误的,表名不能加单引号
三、什么是sql预编译?
在上面的介绍中提到了很多次的sql预编译,sql预编译就是在数据库驱动在发送sql语句和参数给DBMS之前对sql语句进行编译,这样DBMS在执行sql语句就不需要重新编译