mybatis异常invalid comparison: java.util.Date and java.lang.String

本文解决了一个在使用MyBatis 3.3.0版本时出现的日期与字符串比较导致的异常问题,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


严重: Servlet.service() for servlet [spring] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 

### Error querying 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] with root cause
java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
at org.apache.ibatis.ognl.OgnlOps.compareWithConversion(OgnlOps.java:93)
at org.apache.ibatis.ognl.OgnlOps.isEqual(OgnlOps.java:143)
at org.apache.ibatis.ognl.OgnlOps.equal(OgnlOps.java:802)
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.TrimSqlNode.apply(TrimSqlNode.java:55)
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:292)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:134)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:434)
at com.sun.proxy.$Proxy12.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:231)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
at com.sun.proxy.$Proxy13.listbrandInParam(Unknown Source)
at com.wskj.ssm.service.impl.BrandSercieImpl.listBrand(BrandSercieImpl.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy16.listBrand(Unknown Source)
at com.wskj.ssm.controller.BrandController.list(BrandController.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:745)

//****************************************************************************************************************

看样子是因为类型不符合, 但是想了想, Date类型对应MySQL的datetime, 以及mapper中jdbcType都没问题啊. 而且完全一样的东西在原工程中是完全正常的. 既然都是一样的代码, 那就找找俩工程有啥不一样的吧

首先是MySQL jar版本不同. 换成原工程中的版本也无效. 然后是mybatis jar版本不一样, 换成原工程中的版本问题就解决了!

原工程中配置的是mybatis-3.2.8, 而我测试工程中用的是mybatis-3.3.0.后来在网上找了一下才知道, 原来这是mybatis 3.3.0中对于时间参数进行比较时的一个bug. 如果拿传入的时间类型参数与空字符串''进行对比判断则会引发异常. 所以在上面的代码中去该该判断, 只保留非空判断就正常了


//***************************************************************************************************************


例如:在xxMapper.xml的把

<select id="countbrandInParam" resultType="long" parameterType="map">
SELECT count(*) FROM Brand
  <where>
 
  <if test="brandName!=null and brandName!=''">
  and BrandName like concat('%', #{brandName}, '%')
  </if>
  <if test="beginTime!=null and beginTime!=''">
  and brandEnterTime > #{beginTime}
  </if>
  <if test="endTime!=null and endTime!=''">
  and brandEnterTime &lt; #{endTime}
  </if>
  </where>
</select>

换成


<select id="countbrandInParam" resultType="long" parameterType="map">
SELECT count(*) FROM Brand
  <where>
 
  <if test="brandName!=null and brandName!=''">
  and BrandName like concat('%', #{brandName}, '%')
  </if>
  <if test="beginTime!=null">
  and brandEnterTime > #{beginTime}
  </if>
  <if test="endTime!=null">
  and brandEnterTime &lt; #{endTime}
  </if>
  </where>
</select>

### Java中正确比较`java.util.Date`和`java.lang.String` 在Java开发过程中,如果尝试直接比较`java.util.Date`对象和`java.lang.String`对象,则会抛出`java.lang.IllegalArgumentException: invalid comparison`异常。这是因为这两种类型的底层数据结构不同,无法直接进行比较操作[^1]。 #### 原因分析 当使用MyBatis框架时,可能会遇到如下场景:SQL语句中的条件判断部分涉及日期字段的非空校验。例如,在XML映射文件中可能有类似的代码片段: ```xml <if test="createTime != null and createTime != ''"> and create_time=#{createTime} </if> ``` 这里的逻辑问题在于,`createTime`是一个`java.util.Date`类型的变量,而表达式`createTime != ''`试图将其与一个字符串(即空字符串`''`)进行比较。这种跨类型的操作违反了Java的数据类型规则,因此会导致运行时异常[^2]。 #### 正确处理方式 为了实现正确的比较行为,可以采用以下方法之一来解决问题: ##### 方法一:仅验证`Date`对象是否为空 对于大多数业务需求而言,只需要确认传入的参数是否存在即可。可以通过移除不必要的字符串比较逻辑完成修正。修改后的代码如下所示: ```xml <if test="bean.joinTime != null"> join_time= #{bean.joinTime}, </if> <if test="bean.lastLoginTime != null"> last_login_time=#{bean.lastLoginTime}, </if> ``` 此更改确保不会发生非法类型转换的情况,并且保留了必要的功能——检查输入值的有效性[^4]。 ##### 方法二:将`String`解析为`Date` 如果有特殊需求确实需要对比两个时间点的信息,则应先统一两者的表示形式再执行进一步运算。通常做法是从原始字符串创建一个新的`Date`实例用于后续计算过程。下面展示了一个简单的例子说明这一思路的具体实施步骤: ```java import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateComparisonExample { public static void main(String[] args) throws ParseException { String dateString = "2023-10-05"; // 示例日期字符串 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date dateFromString = sdf.parse(dateString); // 将字符串转为Date对象 Date currentDate = new Date(); // 获取当前系统时间作为另一个待比较的时间点 int result = dateFromString.compareTo(currentDate); if (result < 0){ System.out.println("给定日期早于今天!"); }else if(result == 0){ System.out.println("给定日期等于今天!"); }else{ System.out.println("给定日期晚于今天!"); } } } ``` 注意这里引入了`SimpleDateFormat`类帮助我们定义期望的格式模式以便顺利完成从文本到实际日历实体之间的转变工作流程[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值