mybatis if test对Intger判空的坑、原理及解决方法

问题描述

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>
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值