Mybatis占位符${}和#{}的区别
区别的表象
Mybatis占位符$和#,对大多数使用者来说,最直接的区别是: $占位符直接替换真实的值,无法避免SQL注入的漏洞. #占位符是在preparestatement的时候,使用占位符替换真实的值,可以避免SQL注入的漏洞. 因此,大多数的情况下,建议使用的是#占位符.
$占位符只是替换
$占位符的SQL,会创建DynamicSqlSource对象, DynamicSqlSource对象的变量替换,使用的是直接替换逻辑.
在做占位符替换的时候,会走TextSqlNode的handleToken方法:
@Override
public String handleToken(String content) {
Object parameter = context.getBindings().get("_parameter");
if (parameter == null) {
context.getBindings().put("value", null);
} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
context.getBindings().put("value", parameter);
}
Object value = OgnlCache.getValue(content, context.getBindings());
String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null"
checkInjection(srtValue);
return srtValue;
}
#占位符替换为?留给Preparestatement.
#占位符的SQL,会创建RawSqlSource对象.RawSqlSource对象的变量替换,使用的是preparestatement变量?替换逻辑.
在做占位符替换的时候,走ParameterMappingTokenHandler类的handleToken方法:
@Override
public String handleToken(String content) {
parameterMappings.add(buildParameterMapping(content));
return "?";
}
原因解释(上源代码)
XMLLanguageDriver.java类
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
// issue #3
if (script.startsWith("<script>")) {
XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());
return createSqlSource(configuration, parser.evalNode("/script"), parameterType);
} else {
// issue #127
script = PropertyParser.parse(script, configuration.getVariables());
TextSqlNode textSqlNode = new TextSqlNode(script);
if (textSqlNode.isDynamic()) {
return new DynamicSqlSource(configuration, textSqlNode);
} else {
return new RawSqlSource(configuration, script, parameterType);
}
}
}