【MyBatis使用】mapper.xml 文件内<if test>标签判断参数值不等于null和空 当参数值为 0 时筛选条件失效原因分析(源码探究)
這個問題有不少小伙伴遇到過,也給出了解決方案,但是沒有探究原因,這次讀一下源碼,看看原因在哪里。
1. 條件失效情況復現
- Mapper.xml內的動態SQL如下【偽代碼】
- 調用動態SQL的方法如下【偽代碼主要是顯示一下傳遞的參數值】
查看查詢結果會發現對 viewId 沒有進行篩選。
2. 解決方法
去掉判斷條件 and viewId != '' 即可。
<select id="getInfoList" parameterType="java.util.Map" resultType="java.util.Map">SELECT*${schemaName}${tableName}<where><if test="viewId != null">AND viewid = #{viewId}</if></where></select>3. 源碼解析
到底是為什么呢?我們找到 Mybatis 的 IfSqlNode 對象:
下邊是打斷點進行的參數追蹤:
evaluator.evaluateBoolean(test, context.getBindings()) 為 true 時當前節點才會被應用。
進入 evaluateBoolean(test, context.getBindings()) 方法。
進入 OgnlCache.getValue(expression, parameterObject) 方法。
關鍵方法出現了:Ognl.getValue(parseExpression(expression), context, root);
我們找到 Ognl.getValue(parseExpression(expression), context, root)方法。
中間省略了部分方法,省略的方法主要是查找參數名稱和參數值,不重要故未貼出。還有判斷節點類型的過程,例子中用的的都是不等于類型的節點。下邊的方法真正開始對表達式兩側的數值進行比較了。前半段的 viewId != null 不再貼出,只截圖有問題的后半段:
進入最核心的方法比較方法 compareWithConversion(Object v1, Object v2)
看一下轉換的過程:
問題的核心代碼:
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);}}}由于 "".length() = 0,傳遞的參數 viewId 值是 0?? 時 viewId != '' 就變成 0.0 != 0.0 這個自然是 false 此時,篩選條件不起作用就不足為奇了。
為什么會出現這種情況?是框架問題嗎? 感覺不是的,我們在編程的時候,對數值類型值的判斷本身就不應該使用 =='' 或者 !=''這樣的條件。
總結
以上是生活随笔為你收集整理的【MyBatis使用】mapper.xml 文件内<if test>标签判断参数值不等于null和空 当参数值为 0 时筛选条件失效原因分析(源码探究)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java报错】MultipartFil
- 下一篇: 【Java报错】记录一次调用递归方法导致