Mybatis 0 != ““ 引发的问题

在一次项目中,执行一次修改状态的SQL,发现修改状态为0时总是修改不成功,跟踪代码发现以下内容

关键因素

1.属性为Int类型,且值为0

2.mybatis动态sql中使用了<if test="param != null and param !=''">

原因分析

问题主要出在 DynamicSqlSource 这个类中,对sql的拼接

发现在这一步返回的sql就已经缺失了我想要的param

SqlNode.apply()有很多实现方法

在mybatis启动初始化SqlSessionFactoryBean的时候就对xml文件中的sql做了结构化的编译

比如我的一个sql被处理成SqlNode对象时是这样的

所以定位本文问题的话,我们重点关注 IfSqlNode

    public boolean apply(DynamicContext context) {
        //这里对表达式做计算
        if (this.evaluator.evaluateBoolean(this.test, context.getBindings())) {
            this.contents.apply(context);
            return true;
        } else {
            return false;
        }
    }

 

通过调用了 SimpleNode.getValue

它的实现类根据不同表达式分为一系列的 ASTXXXX的实现类

我使用类!= 根据类名就可以确定到是 ASTNotEq

class ASTNotEq extends ComparisonExpression {
    public ASTNotEq(int id) {
        super(id);
    }

    public ASTNotEq(OgnlParser p, int id) {
        super(p, id);
    }

    protected Object getValueBody(OgnlContext context, Object source) throws OgnlException {
        //获取表达式前半部分
        Object v1 = this._children[0].getValue(context, source);
        //获取表达式后半部分
        Object v2 = this._children[1].getValue(context, source);
        return OgnlOps.equal(v1, v2) ? Boolean.FALSE : Boolean.TRUE;
    }

    public String getExpressionOperator(int index) {
        return "!=";
    }

    public String getComparisonFunction() {
        return "!ognl.OgnlOps.equal";
    }
}

进入到 OgnlOps.isEqual当表达式为 0 != "" 可以判断会进入

result = compareWithConversion(object1, object2) == 0
    public static boolean isEqual(Object object1, Object object2) {
        boolean result = false;
        if (object1 == object2) {
            result = true;
        } else if (object1 != null && object2 != null) {
            int i;
            int icount;
            if (object1.getClass().isArray()) {
                if (object2.getClass().isArray() && object2.getClass() == object1.getClass()) {
                    result = Array.getLength(object1) == Array.getLength(object2);
                    if (result) {
                        i = 0;

                        for(icount = Array.getLength(object1); result && i < icount; ++i) {
                            result = isEqual(Array.get(object1, i), Array.get(object2, i));
                        }
                    }
                }
            } else {
                i = getNumericType(object1);
                icount = getNumericType(object2);
                if (i != 10 || icount != 10 || object1 instanceof Comparable && object2 instanceof Comparable) {
                    result = compareWithConversion(object1, object2) == 0;
                } else {
                    result = object1.equals(object2);
                }
            }
        }

        return result;
    }

根据我们的入参数,会继续调用 OgnlOps.getNumericType(Object value),这个方法也很通俗易懂

参数为0返回的是4,参数为“”返回了10

然后调用 getNumericType( 4, 10, true)

所以结果为10

在OgnlOps.compareWithConversion中 结果为10,且 t1或t2为10 那么就会返回标签 label75

                case 10:
                    if (t1 != 10 || t2 != 10) {
                        break label75;
                    }

                    if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
                        result = ((Comparable)v1).compareTo(v2);
                        break;
                    }

                    if (!(v1 instanceof Enum) || !(v2 instanceof Enum) || v1.getClass() != v2.getClass() && ((Enum)v1).getDeclaringClass() != ((Enum)v2).getDeclaringClass()) {
                        throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
                    }

                    result = ((Enum)v1).compareTo(v2);
                    break;

 

那么两个参数都会被转为double数值,最终都为 0.0D

    public static double doubleValue(Object value) throws NumberFormatException {
        if (value == null) {
            return 0.0D;
        } else {
            Class c = value.getClass();
            if (c.getSuperclass() == Number.class) {
                return ((Number)value).doubleValue();
            } else if (c == Boolean.class) {
                return (Boolean)value ? 1.0D : 0.0D;
            } else if (c == Character.class) {
                return (double)(Character)value;
            } else {
                String s = stringValue(value, true);
                return s.length() == 0 ? 0.0D : Double.parseDouble(s);
            }
        }
    }

 

及 compareWithConversion(0,"")将返回true

所以 ASTNotEq将返回false

最终在 IfSqlNode中将此表达式过滤了

结论

int类型在动态sql中不应该使用  param !=''" 的判断表达式

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值