美文网首页
mybatis踩坑之"time!=''"

mybatis踩坑之"time!=''"

作者: kevin0016 | 来源:发表于2019-07-29 15:09 被阅读0次

    关于内部mybatis升级版本(3.2.8->3.3.1)之后出现的问题说明

    关于时间类型的在xml里面进行判空抛的异常

    mybatis版本是3.3.1

    错误代码

        <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!=''这个判断,代码中传入的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
    

    其中重点的错误信息提示是invalid comparison: java.util.Date and java.lang.String说明类型转换异常,直接找到错误信息的锁定位的源码查看

    源码路径为: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‘’此处是添加了这样的一个判断导致抛出这样的异常

    对比3.2.8版本中的代码实现

    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;
        }
    

    严格来说这里其实并不是mybatis的源码,而是ognl解析xml出来的代码,mybatis的3.3.X版本主要升级点就是把ognl的版本升级到了3.0.11,这个版本优化了对于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的规范,有些写法可能目前并未进行校验,但是后期版本很有可能添加上这种判断。

    另外对于业务代码,这里有明显的逻辑性错误,传入的是date类型,却要进行空串判断,这种逻辑不能出现,尤其是框架本身并未明说支持这种写法的情况下,谨慎使用。

    相关文章

      网友评论

          本文标题:mybatis踩坑之"time!=''"

          本文链接:https://www.haomeiwen.com/subject/bxpbrctx.html