- 起因
之前在一个Mapper文件中写了这样一个if标签,结果当参数为0时不论如何if标签的判断都是false,打印sql也发现当参数为0时这个条件会不起作用,因此查看了一下MyBatis中相关的源码,if标签如下:
<if test="backCarType != null and backCarType != ''">
and m.back_car = #{backCarType,jdbcType=BIT}
</if>
- MyBatis 创建BoundSql的过程
上文提到了MappedStatement这个类,这个类中有一个getBoundSql()方法,现在来跟踪一下这个方法:
- MappedStatement.getBoundSql(Object parameterObject)
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
- DynamicSqlSource.getBoundSql(Object parameterObject)
public BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
}
重点关注这个rootSqlNode,因为它就是解析我们写在mapper文件中的各种标签,比如if、choose、foreach等,接下来看一下是怎么解析if标签的:
public class IfSqlNode implements SqlNode {
private final ExpressionEvaluator evaluator;
private final String test;
private final SqlNode contents;
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
}
@Override
public boolean apply(DynamicContext context) {
if (evaluator.evaluateBoolean