最近在使用Mybatis的過程中遇到了一個奇怪的問題,如下所示:查詢SQL中的一個狀態條件,在param.sendstate=0或10時,單獨處理.
<choose> <when test="param.sendstate!=null and param.sendstate == 10"> and (SendState = 2 and (RESPONSETYPETEXT is null or RESPONSETYPETEXT ='')) </when> <when test="param.sendstate!=null and param.sendstate == 0"> and (SendState = 0 or SendState = '' or SendState is null) </when> <otherwise> <if test="param.sendstate!=null and param.sendstate!=''"> and SendState = #{param.sendstate} </if> </otherwise> </choose>
但是,當param.sendstate為空字符串時,通過控制台打印的SQL發現執行的SQL是:

也就是說此時 param.sendstate == 0結果是true
這個問題困擾了我半天,最后改成如下形式解決
<if test="param.state!=null and param.state!=''"> <choose> <when test="param.state == 10"> and (state = 10 and responsetext is null) </when> <when test="param.state == 0"> and (state = 0 or state is null) </when> <otherwise> and state = #{param.state} </otherwise> </choose> </if>
由於時間緊急,沒有深入去研究這個問題.后來看到了這篇文章
Mybatis參數Integer類型值為0 源碼處理
http://www.cnblogs.com/gushen-super/archive/2018/06/28/9238161.html
簡單跟蹤了下代碼,明白了問題在哪.
Mybatis在處理 if 標簽時,使用OGNL表達式處理並返回表達式的結果.
條件:param.sendstate == 0,此時param.sendstate是空字符串
OGNL在處理 == 運算時,最終調用的是 OgnlOps類的compareWithConversion方法
public static int compareWithConversion(Object v1, Object v2) { int result; if (v1 == v2) { result = 0; } else { int t1 = getNumericType(v1); int t2 = getNumericType(v2); int type = getNumericType(t1, t2, true); switch(type) { case 6: result = bigIntValue(v1).compareTo(bigIntValue(v2)); break; case 9: result = bigDecValue(v1).compareTo(bigDecValue(v2)); break; case 10: if (t1 == 10 && t2 == 10) { if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) { result = ((Comparable)v1).compareTo(v2); break; } throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName()); } case 7: case 8: double dv1 = doubleValue(v1); double dv2 = doubleValue(v2); return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1); default: long lv1 = longValue(v1); long lv2 = longValue(v2); return lv1 == lv2 ? 0 : (lv1 < lv2 ? -1 : 1); } } return result; }
compareWithConversion方法有兩個Object類型的參數v1和v2,帶入上面的條件,即
v1 = param.sendstate(空字符串)
v2 = 0
經過getNumericType方法的處理,最終進入case=8里面處理,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 (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); } } }
可以看到,當value = 0 的時候,結果值為0.0,當value為空字符串時,結果值為0.0D
所以dv1 == dv2 結果為true,compareWithConversion方法的最終返回值為0,即相等.

