在Mybatis的Mapper.xml文件中,获取传递参数的值的方式有两种:**#{variable_name}** 和 **${variable_name}**。这两种取值方式的不同点有如下几个方面。
#### **1. #{ }是预编译处理,${ }是字符串替换。**
Mybatis在对sql语句进行预编译时前,会对sql进行动态解析,解析为一个 BoundSql对象,也是在此时对动态SQL进行处理的。在动态SQL解析阶段,#{ } 和 ${ }会有不同的表现。Mybatis在动态SQL解析阶段处理#{ }时,会将sql中的#{ }替换为?号,然后调用PreparedStatement的set方法来赋值;而在处理${ }时,直接把${}替换成变量的值,即会将我们传入的参数当做String字符串填充到我们的语句中。 ${ } 变量的替换阶段是在动态 SQL 解析阶段,而 #{ }变量的替换是在 DBMS 中。不妨举个例子:
---
- 在mapper.xml中的SQL语句使用#{ }取参数时为下面的语句:
```xml
<!--#{ }取参数-->
<select id="selectComputer" resultType="cn.java.entity.Computer" parameterType="java.util.Map">
select * from computers where brand=#{brand} and memory_size=#{memory_size};
</select>
```
那么它在sql动态解析阶段表现为下面的语句:
```SQL
select * from computers where brand=? and memory_size=?;
```
---
- 在mapper.xml中的SQL语句使用${ }取参数时为下面的语句:
```xml
<!--${ }取参数-->
<select id="selectComputer" resultType="cn.java.entity.Computer" parameterType="java.util.Map">
select * from computers where brand="${brand}" and memory_size=${memory_size};
</select>
```
那么它在sql动态解析阶段表现为下面的语句:
```SQL
select * from computers where brand="dell" and memory_size=8;
```
---
#### **2. #{ }和${ }填充数据的方式不一样**
#{ }将传入的数据视为字符串,会自动添加"",${ }将传入的数据直接显示在sql语句中。例如在mapper.xml中的SQL语句使用${ }和#{ }取值时为下面的语句:
```xml
<!--#{ }取参数-->
<select id="selectOrder" resultType="cn.java.entity.Order" parameterType="java.util.Map">
select company, orderNumber from orders order by #{orderByParameter};
</select>
<!--${ }取参数-->
<select id="selectOrder" resultType="cn.java.entity.Order" parameterType="java.util.Map">
select company, orderNumber from orders order by ${orderByParameter};
</select>
```
则解析结果为
```SQL
---#{ }取参数
select company, orderNumber from orders order by "company";
---${ }取参数
select company, orderNumber from orders order by company;
```
#### **3. #{ }可以防止SQL注入,${ }不可以**
如果Mapper.xml中的SQL语句如下:
```xml
<select id="selectComputer" resultType="cn.java.entity.Computer" parameterType="java.util.Map">
select * from ${tableName} where brand=#{brand};
</select>
```
参数tableName为:
```sql
computers; delete computers; --
```
参数brand为:
```SQL
dell
```
则动态解析之后 sql 如下:
```SQL
select * from computers; delete computers; -- where brand=dell;
```
--之后的语句被注释掉,而原本查询的语句变成了查询所+删表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机。
#### **总结:**
1. #{ }将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
2. ${ }将传入的数据直接显示生成在sql中。
3. #{ }方式能够很大程度防止sql注入。
4. ${ }方式无法防止Sql注入。
5. ${ }方式一般用于传入数据库对象,例如传入表名。
6. #{ }方式一般用于传入字段值。
7. 一般能用#{ }的就别用${ }。

Mybatis中的#{ }和${ }的理解