mybatis空字符串和0相比为true

  • Post author:
  • Post category:其他




问题

<if test="field!=null and field!=''">
	and field=#{field}
</if>

mybatis中经常会用这种写法,这种写法一般都说,field是String类型.如果field在接口层是一个Integer(之所以是Integer,是历史代码不规范),并且是0的话,这个if条件是true 还是 false呢?

咋一看,感觉应该是true,因为0!=null && 0!=’’,但是实际上这个是false.这个场景下,mybatis认为空字符串和0是相等.这个结论很难以相信,是mybatis刻意为之,还是代码的bug?debug了下mybatis源码,找到了问题根源:



源码

mybatis源码->org.apache.ibatis.ognl.ASTEq->getValueBody->OgnlOps.equal(v1, v2)->OgnlOps.isEqual->compareWithConversion

result = compareWithConversion(object1, object2, true) == 0 || object1.equals(object2)

// compareWithConversion方法通过如下代码去比较
case 8:
double dv1 = doubleValue(v1);
double dv2 = doubleValue(v2);
return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1);

// doubleValue的实现如下:
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 (double)((Boolean)value ? 1 : 0);
            } else if (c == Character.class) {
                return (double)(Character)value;
            } else {
            	// Integer的话,会走这个elase分支
                String s = stringValue(value, true);
                // 空字符串的长度是0,所以空字符串被转换成0.0D
                return s.length() == 0 ? 0.0D : Double.parseDouble(s);
            }
        }
    }



结论


关键在于 return s.length() == 0 ? 0.0D : Double.parseDouble(s); 这行代码,空字符串被转成了0.0D,0也被转成了0.0D,导致( 0 == ‘’ )为true.

1.对于Integer类型的字段如果加上field!=’’的判断,会不知不觉的导致0判断失败,导致field字段无法参与where过滤;

2.如果field是insert的字段,if判断失败,会导致field==0的时候,field字段无法插入。



解决办法:

1.将field字段改为String类型

2.去掉field!=’‘的判断,值得注意的是,现在主流的自动生成mybatis的工具,都会对Integer字段加上这个field!=’’的判断



版权声明:本文为u014225427原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。