mybatis if test非空判斷數字0爲什麼是false

今天工作中發現一個Long類型的參數沒有傳到sql中去,在sql xml配置文件中是使用if test標籤判斷:

 <if test="version != null and version != ''">xxxxx</if>

通過debug發現參數中的version是有值的,但出來的sql語句就沒有這個version

 

網上查了一些有不少同樣這樣的問題,大致解決辦法分兩種:

1、去掉空字符串判斷

         <if test="version != null">xxxxx</if>

2、添加0值判斷

         <if test="version != null and version != '' or version == 0">xxxxx</if>

這兩種方法都是可以的,在我看來是這樣,如果這個version類型和我的情況一樣,是包裝類型而不是基本數據類型的話,第一種就足夠了,而且更貼近實際,因爲包裝類型除了有值的情況就是null,不會爲""空字符串的,String類型不在我討論的範圍內,標題已經說了是數字0,況且如果是String的話就不會有這個問題了。

 

知道了怎麼解決這個問題,那就想知道爲什麼這個問題會出現,當然要查看mybatis的源碼了,

sql語句是通過獲取BoundSql來的(網上查看mybatis層次結構),這個是通過方法getBoundSql(),這個方法定義在一個接口SqlSource,它有五個實現,從命名上看應該是找DynamicSqlSource,

<img/>暫時缺少圖片

if判斷的這種屬於動態的sql所以直接找它了

這裏面有句:rootSqlNode.apply(content);這個是添加動態sql 的,點進去查看

apply也是在一個接口裏,查看實現,各種和標籤有關的命名實現,這個標籤是if當然就是找IfSqlNode了,它裏面的實現是通過evaluator.evaluateBoolean()方法判斷的,點進去繼續看

發現一行重要的代碼:

if(value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);

現在真相大白了,不管是Inteter還是Long,只要是值爲0,都會判斷爲false

 

真的很抱歉,上面的分析錯了,早上來了之後有四個瀏覽,立刻隱藏了這篇文章準備修改,希望那四位網友能再看到更正,上面的分析是在昨天晚上下班後,現在我又看了一遍昨天打開的源碼:

上面的value其實是test後面的表達式的返回值,而不是傳入的version參數,test後面的表達式如果只寫一個0的話就會走上面的if判斷,直接返回false,但眼前的情況是version爲0,test後面的表達式就是:0 != null and 0 != '',這個表達式是由org.apache.ibatis.scripting.xmltags.OgnlCache類的getValue(String expression,Objec root)方法得來,下載了ognl源碼包關聯之後從新走的debug追蹤了一下,還是從上面IfSqlNode中的apply方法判斷說起:

(DynamicContext context) {
  (.evaluateBoolean(context.getBindings())) {
    .apply(context)}
  }

進入evaluateBoolean方法:

(String expressionObject parameterObject) {
  Object value = OgnlCache.(expressionparameterObject)(value Boolean) (Boolean) value(value Number) !BigDecimal(String.(value)).equals(BigDecimal.)value != }

這裏面expression參數就是“version != null and version != ''”這個getValue方法裏面就是調用Ognl包中的方法處理之後返回的一個值,進去這個getValue方法中

Object (String expressionObject root) {
  {
    Map<ObjectOgnlCla***esolver> context = Ognl.(rootOgnlCla***esolver())Ognl.((expression)contextroot)} (OgnlException e) {
    BuilderException(+ expression + + ee)}
}

這裏面parseExpression(expression)是解析表達式的,沒有決定到最終結果,還是要進去看getvalue方法,裏面調用了好多層,debug下一步一步進去追蹤,會發現下面的關鍵代碼:

Object getValueBody(OgnlContext contextObject source) OgnlException {
    Object v1 = .children[].getValue(contextsource)Object v2 = .children[].getValue(contextsource)OgnlOps.equal(v1v2)?Boolean.FALSE:Boolean.TRUE}

上面的表達式是version != null and version != '',這個方法是在一個for循環裏調用的,分別是0和null的比較,0和""的比較,第一次比較肯定是true不用說了,第二次的時候v1就是0,v2就是"",繼續查看這裏的OgnlOps.equal()方法

equal(Object v1Object v2) {
    v1 == ?v2 == :(v1 != v2 && !isEqual(v1v2)?(v1 Number && v2 Number?((Number)v1).doubleValue() == ((Number)v2).doubleValue():):)}

0和null判斷爲false,執行:後面的,關鍵取決於isEqual()方法了,進去這方法裏又能看到一個方法

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

進去查看

compareWithConversion(Object v1Object v2equals) {
    result(v1 == v2) {
        result = } {
            t1 = getNumericType(v1)t2 = getNumericType(v2)type = getNumericType(t1t2)(type) {
        :
            result = bigIntValue(v1).compareTo(bigIntValue(v2)):
            result = bigDecValue(v1).compareTo(bigDecValue(v2)):
            (t1 == && t2 == ) {
                (v1 != && v2 != ) {
                    (v1.getClass().isAssignableFrom(v2.getClass()) || v2.getClass().isAssignableFrom(v1.getClass())) {
                        (v1 Comparable) {
                            result = ((Comparable)v1).compareTo(v2)}

                        (equals) {
                            result = v1.equals(v2)?:}
                    }

                    (!equals) {
                        IllegalArgumentException(+ v1.getClass().getName() + + v2.getClass().getName())}

                    result = } {
                    var10000 = v1 != v2}
            }
        :
        :
                 dv1 = doubleValue(v1)dv2 = doubleValue(v2)dv1 == dv2?:(dv1 < dv2?-:):
            lv1 = longValue(v1)lv2 = longValue(v2)lv1 == lv2?:(lv1 < lv2?-:)}
    }

    result}

參數一個是0,一個是"",最終debug會走進case 8 裏面,0和“”都會被轉成double進行比較,都會變成0.0,這就是mybati中if test 0!=""判定爲false的原因

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章