mybatis踩坑之"time!=''"

關(guān)于內(nèi)部mybatis升級版本(3.2.8->3.3.1)之后出現(xiàn)的問題說明

關(guān)于時(shí)間類型的在xml里面進(jìn)行判空拋的異常

mybatis版本是3.3.1

錯(cuò)誤代碼

    <update id="updateUserProductDelayStatusAndAuditEndTime"
        parameterType="com.koolearn.sharks.model.UserProductDelay">
        update pe_user_product_delay
        set
        status = #{status,jdbcType=TINYINT},
        update_time = now(),
        update_uid = #{updateUid,jdbcType=VARCHAR},
        <if test="null != auditEndTime and auditEndTime!=''">
            audit_end_time = #{auditEndTime,jdbcType=TIMESTAMP},
        </if>
        update_username = #{updateUsername,jdbcType=VARCHAR}
        where id = #{id,jdbcType=INTEGER}
    </update>

此處需要注意的是null != auditEndTime and auditEndTime!=''這個(gè)判斷,代碼中傳入的auditEndTimedate類型,此處異常信息為

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
### Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:368)
    at com.sun.proxy.$Proxy26.update(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:254)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:55)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
    at com.sun.proxy.$Proxy94.updateUserProductDelayStatusAndAuditEndTime(Unknown Source)
    at com.koolearn.sharks.service.impl.UserProductDelayServiceImpl.updateUserProductDelayStatusAndAuditEndTime(UserProductDelayServiceImpl.java:360)
    at com.koolearn.sharks.service.impl.UserProductDelayServiceImpl$$FastClassBySpringCGLIB$$4517d719.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:700)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at com.koolearn.common.dubbo.logger.AccessLoggerInterceptor.invoke(AccessLoggerInterceptor.java:25)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at com.koolearn.common.dubbo.logger.PerformanceLoggerInterceptor.invoke(PerformanceLoggerInterceptor.java:22)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633)
    at com.koolearn.sharks.service.impl.UserProductDelayServiceImpl$$EnhancerBySpringCGLIB$$9e102bd3.updateUserProductDelayStatusAndAuditEndTime(<generated>)
    at com.koolearn.sharks.service.impl.demotest.test2(demotest.java:36)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
### Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:172)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358)
    ... 44 more
Caused by: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
    at org.apache.ibatis.ognl.OgnlOps.compareWithConversion(OgnlOps.java:92)
    at org.apache.ibatis.ognl.OgnlOps.isEqual(OgnlOps.java:142)
    at org.apache.ibatis.ognl.OgnlOps.equal(OgnlOps.java:794)
    at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:53)
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
    at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:61)
    at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
    at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
    at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:494)
    at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:458)
    at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:44)
    at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32)
    at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34)
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)
    at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41)
    at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:279)
    at com.koolearn.framework.mybatis.datasource.plugin.CatPlugin.intercept(CatPlugin.java:27)
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
    at com.sun.proxy.$Proxy168.update(Unknown Source)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:170)
    ... 49 more

其中重點(diǎn)的錯(cuò)誤信息提示是invalid comparison: java.util.Date and java.lang.String說明類型轉(zhuǎn)換異常,直接找到錯(cuò)誤信息的鎖定位的源碼查看

源碼路徑為:org.apache.ibatis.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;
    }

其中v1和v2分別是類型對比中的auditEndTime‘’此處是添加了這樣的一個(gè)判斷導(dǎo)致拋出這樣的異常

對比3.2.8版本中的代碼實(shí)現(xiàn)

public static int compareWithConversion(Object v1, Object v2, boolean equals) {
        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 != null && v2 != null) {
                        if (v1.getClass().isAssignableFrom(v2.getClass()) || v2.getClass().isAssignableFrom(v1.getClass())) {
                            if (v1 instanceof Comparable) {
                                result = ((Comparable)v1).compareTo(v2);
                                break;
                            }

                            if (equals) {
                                result = v1.equals(v2) ? 0 : 1;
                                break;
                            }
                        }

                        if (!equals) {
                            throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
                        }

                        result = 1;
                        break;
                    } else {
                        boolean var10000 = v1 != v2;
                    }
                }
            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;
    }

嚴(yán)格來說這里其實(shí)并不是mybatis的源碼,而是ognl解析xml出來的代碼,mybatis的3.3.X版本主要升級點(diǎn)就是把ognl的版本升級到了3.0.11,這個(gè)版本優(yōu)化了對于xml解析流程

修改方法:

    <update id="updateUserProductDelayStatusAndAuditEndTime"
        parameterType="com.koolearn.sharks.model.UserProductDelay">
        update pe_user_product_delay
        set
        status = #{status,jdbcType=TINYINT},
        update_time = now(),
        update_uid = #{updateUid,jdbcType=VARCHAR},
        <if test="null != auditEndTime">
            audit_end_time = #{auditEndTime,jdbcType=TIMESTAMP},
        </if>
        update_username = #{updateUsername,jdbcType=VARCHAR}
        where id = #{id,jdbcType=INTEGER}
    </update>

直接把判斷空串的部分刪掉即可…

這邊需要注意一下,對于xml的判斷,要符合OGNL的規(guī)范,有些寫法可能目前并未進(jìn)行校驗(yàn),但是后期版本很有可能添加上這種判斷。

另外對于業(yè)務(wù)代碼,這里有明顯的邏輯性錯(cuò)誤,傳入的是date類型,卻要進(jìn)行空串判斷,這種邏輯不能出現(xiàn),尤其是框架本身并未明說支持這種寫法的情況下,謹(jǐn)慎使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,282評論 0 4
  • 標(biāo)簽 如果要配置的標(biāo)簽,那么必須要先配置標(biāo)簽,代表的包的概念。 包含的屬性 name包的名稱,要求是唯一的,管理a...
    偷偷得路過閱讀 1,518評論 0 0
  • mybatis-02(mapper.xml映射文件,動態(tài)sql) 一.mapper xml映射文件 MyBatis...
    小山居閱讀 772評論 0 0
  • 對于java中的思考的方向,1必須要看前端的頁面,對于前端的頁面基本的邏輯,如果能理解最好,不理解也要知道幾點(diǎn)。 ...
    神尤魯?shù)婪?/span>閱讀 907評論 0 0
  • 最近學(xué)習(xí)MyBatis這個(gè)輕量型持久層框架,感覺入門很簡單,但是深層次細(xì)節(jié)配置很多。本篇筆記從 配置文件->例子入...
    Super超人閱讀 735評論 0 1

友情鏈接更多精彩內(nèi)容