问题:
<choose>
<when test="columnStr == '0'">
and a.xx = 'xxx'
</when>
<when test="columnStr == '1'">
and a.xx = 'yyy'
</when>
<otherwise>
and 1 = 1
</otherwise>
</choose>
如果columnStr 为0,判断时候会走到otherwise,
主要是因为mybatis把’0’当成了Character去比较。
解决方案:
方案一:
0外围使用双引号
<when test='columnStr == "0"'>
方案二:
使用toString转成String
<when test='columnStr == '0'.toString()">
方案三:
直接使用int
<when test='columnStr == 0">
原因分析:
可以找下源码org.apache.ibatis.ognl.OgnlOps.compareWithConversion这个方法
public static int compareWithConversion(Object v1, Object v2) {
int result;
if (v1 == v2) {
result = 0;
} else {
double dv2, dv1;
int result, t1 = getNumericType(v1), t2 = getNumericType(v2), type = getNumericType(t1, t2, true);
switch (type) {
case 6:
result = bigIntValue(v1).compareTo(bigIntValue(v2));
return result;
case 9:
result = bigDecValue(v1).compareTo(bigDecValue(v2));
return result;
case 10:
if (t1 == 10 && t2 == 10) {
if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
result = ((Comparable<Object>) v1).compareTo(v2);
} else {
throw new IllegalArgumentException(
"invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
}
return result;
}
case 7:
case 8:
dv1 = doubleValue(v1);
dv2 = doubleValue(v2);
return (dv1 == dv2) ? 0 : ((dv1 < dv2) ? -1 : 1);
}
long lv1 = longValue(v1);
long lv2 = longValue(v2);
return (lv1 == lv2) ? 0 : ((lv1 < lv2) ? -1 : 1);
}
return result;
}
public static String stringValue(Object value, boolean trim) {
String result;
if (value == null) {
result = "" + null;
} else {
result = value.toString();
if (trim) {
result = result.trim();
}
}
return result;
}
public static long longValue(Object value) throws NumberFormatException {
if (value == null) return 0L;
Class<?> c = value.getClass();
if (c.getSuperclass() == Number.class) return ((Number)value).longValue();
if (c == Boolean.class) return ((Boolean)value).booleanValue() ? 1L : 0L;
if (c == Character.class) return ((Character)value).charValue();
return Long.parseLong(stringValue(value, true));
}
public static int getNumericType(int t1, int t2, boolean canBeNonNumeric) {
if (t1 == t2) return t1;
if (canBeNonNumeric && (t1 == 10 || t2 == 10 || t1 == 2 || t2 == 2)) return 10;
if (t1 == 10) t1 = 8;
if (t2 == 10) t2 = 8;
if (t1 >= 7) {
if (t2 >= 7) return Math.max(t1, t2);
if (t2 < 4) return t1;
if (t2 == 6) return 9;
return Math.max(8, t1);
} if (t2 >= 7) {
if (t1 < 4) return t2;
if (t1 == 6) return 9;
return Math.max(8, t2);
} return Math.max(t1, t2);
}
其中调用的方法
public static int getNumericType(Object value) {
if (value != null) {
Class<?> c = value.getClass();
if (c == Integer.class) return 4;
if (c == Double.class) return 8;
if (c == Boolean.class) return 0;
if (c == Byte.class) return 1;
if (c == Character.class) return 2;
if (c == Short.class) return 3;
if (c == Long.class) return 5;
if (c == Float.class) return 7;
if (c == BigInteger.class) return 6;
if (c == BigDecimal.class) return 9;
}
return 10;
}
尝试写了以下代码验证了下
compareWithConversion返0表示相同,所以才导致走的那个判断分支
public static void main(String[] args) {
String test = "0";
System.out.println(OgnlOps.getNumericType(test));
System.out.println(OgnlOps.getNumericType('0'));
System.out.println(OgnlOps.getNumericType(0));
System.out.println(OgnlOps.compareWithConversion(test, '0'));
System.out.println(OgnlOps.compareWithConversion(test, 0));
}
结果:
10
2
4
-1
0