1. 取值范围不同
MyBatis既可以获取执行SQL时插入的请求参数,也可以从主配置文件加载的配置文件中获取配置参数。
#{}
只能获取请求参数的值,无法获取配置参数。
${}
在MyBatis初始化时能获取配置参数,如果没有,执行时再获取请求参数。
2. 处理方式不同
#{}
- 如果SQL中只有
#{}
或者可以被配置参数替换的${}
,那么在初始化时#{}
就被解析成了占位符?
。 - 如果SQL中有动态标签(例如
if
,where
),或者无法被配置参数替换的${}
,那么#{}
在执行SQL时才会被替换成占位符?
。#{}
的值是执行SQL时通过JDBC的Statement根据占位符进行设置。
${}
- 如果可以被配置参数替换,则在初始化时已被配置参数替换,否则在执行SQL时使用请求参数替换。
${}
的值使用参数值直接替换,不做任何特殊处理。
3. 安全性不同
#{}
能够很大程度防止SQL注入。
${}
无法防止SQL注入。
所以,能用#{}
的就别用${}
。
${}
方式一般用于传入数据库对象,例如传入表名,排序字段等。
4. 测试验证
以下是自己做过的一些测试验证场景:
测试场景一:
${}
是否能够获取配置文件中的参数?如果能获取配置参数,那么是初始化时替换${}
还是执行时替换${}
。
测试结果一:
${}
在MyBatis初始化时,获取MyBatis主配置文件中加载的配置参数进行替换。
- SQL中只有
${}
,${}
被替换成配置参数,在所有${}
都被替换的情况下,生成的是静态SQL对象。 - SQL中只有
${}
和#{}
,${}
被替换成配置参数,在所有${}
都被替换的情况下,#{}
会被替换成?
,且生成静态SQL对象。 - SQL中存在
${}
和动态标签,${}
无论在动态标签内或者外,${}
都被替换成配置参数,生成动态SQL对象。 - SQL中存在
${}
、#{}
和动态标签,${}
被替换成配置参数,#{}
没有被替换成?
,生成动态SQL对象。
测试结论一:
在MyBatis初始化阶段,解析XML配置文件的过程中,会对${propertyName}
占位符做解析,如果能够在配置参数中获取到key=propertyName
的值,那么就会使用配置参数值替换${propertyName}
,否则保留。所以在xxxMapper.xml
中使用${propertyName}
获取参数时,需要考虑是获取配置文件中的值,还是获取SQL执行时传入的请求参数值。这可能会出现意想不到的结果。
测试场景二:
如果SQL中有动态标签或者${}
符号,且${}
不会被配置参数替换时,SQL中的#{}
在初始化时替换成?
,还是在执行时被替换成?
。
测试结果二:
在MyBatis初始化过程中的测试结果:
- SQL中仅有
#{}
,#{}
被替换成?
。 - SQL中有
#{}
和${}
,#{}
没有被替换成?
。 - SQL中有
#{}
和动态标签,#{}
无论在动态标签内还是外,都没有被替换成?
。 - SQL中有
#{}
和${}
、动态标签,#
{}没有被替换成?
。
在SQL执行过程中的测试结果:
- SQL中仅有
#{}
,#{}
在初始化阶段就已被替换成了?
。 - SQL中有
#{}
和${}
,#{}
被替换成?
,${}
被替换成参数值。 - SQL中有
#{}
和动态标签,#{}
被替换成?
,动态标签根据参数被解析。 - SQL中有
#{}
、${}
和动态标签,#{}
被替换成?
,${}
被替换成参数值,动态标签根据参数被解析。