文章目录
- 问题描述
- 源码分析
- 解决方法
问题描述
Mybatis在进行<if test="status!= null and status!= '' ">
非空判断操作时,如果status为0的时候,该判断条件的值为false
写法如下:
<select id="countByBySearchCondition" resultType="java.lang.Integer">
select count(1)
from test_user
<where>
delete_flag = 0
<if test="status!= null and '' != status">
and status= #{status}
</if>
</where>
</select>
说明
:当status传入0时,查询语句中并没有把and status=0这个条件拼接上
原理:
当if中的对象为Number类型时,将使用双精度浮点类型与0比较,如果不等于0则视为true,否则视为false。
源码分析
mybatis中<if test="status!= null and '' != status">
的解析是org.apache.ibatis.scripting.xmltags.IfSqlNode类进行解析处理的
package org.apache.ibatis.scripting.xmltags;
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();
}
public boolean apply(DynamicContext context) {
if (this.evaluator.evaluateBoolean(this.test, context.getBindings())) {
this.contents.apply(context);
return true;
} else {
return false;
}
}
}
判断逻辑在this.evaluator.evaluateBoolean
中,test就是"status!= null and '' != status"
public boolean evaluateBoolean(String expression, Object parameterObject) {
Object value = OgnlCache.getValue(expression, parameterObject);
if (value instanceof Boolean) {
return (Boolean)value;
} else if (value instanceof Number) {
return (new BigDecimal(String.valueOf(value))).compareTo(BigDecimal.ZERO) != 0;
} else {
return value != null;
}
}
继续进入OgnlCache.getValue(expression, parameterObject)
方法
public static Object getValue(String expression, Object root) {
try {
Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, (TypeConverter)null);
return Ognl.getValue(parseExpression(expression), context, root);
} catch (OgnlException var3) {
throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + var3, var3);
}
}
关键解析在Ognl.getValue(parseExpression(expression), context, root)
方法,先看parseExpression(expression)
方法
private static Object parseExpression(String expression) throws OgnlException {
Object node = expressionCache.get(expression);
if (node == null) {
node = Ognl.parseExpression(expression);
expressionCache.put(expression, node);
}
return node;
}
这个方法实际上就是解析了一下"status!= null and '' != status"
这段内容,然后返回给Ognl.getValue方法来处理
验证
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
public class Test1 {
public static void main(String[] args) throws OgnlException {
System.out.println(Ognl.parseExpression("0 != null and 0 != ''"));
}
}
执行结果:
(0 != null) && (0 != "")
可以看到"0 != null and 0 != ''"
先是被解析为了(0 != null) && (0 != "")
这样一段内容,接着我们放入Ognl.getValue
方法中再来看看结果
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
public class Test1 {
public static void main(String[] args) throws OgnlException {
Object obj1 = Ognl.getValue(Ognl.parseExpression("0 != null and 0 != ''"),null);
Object obj2 = Ognl.getValue(Ognl.parseExpression("1 != null and 1 != ''"),null);
System.out.println(obj1);
System.out.println(obj2);
}
}
执行结果:
false
true
测试表明:当if表达式中的值为Number类型且值为0时,表达式结果返回为false。
查询Ognl官方文档验证
文档地址:https://commons.apache.org/proper/commons-ognl/language-guide.html
文档中说明,当if中的对象为Number类型时,将使用双精度浮点类型与0比较,如果不等于0则视为true,否则视为false。
解决方法
方式一: 用 <if test="status!= null">
进行判断即可
<if test="status!= null">
and status= #{status}
</if>
方式二:
<if test="status!= null and status!= '' or status == 0">
and status= #{status}
</if>