mybatis可以帮我们自动映射字段,在mapper.xml文件中,我们可以不用去写jdbcType来明确指定数据类型,它会自动解析成相对应的java数据类型,每次在使用了mybatis-generator之后,出于强迫症,我还主动将默认生成的jdbcType给去掉了,一直没出过问题,今天却碰到了一个问题:

出问题的业务场景中,需要根据不同的角色查询不同的订单数据,所以我就直接将角色ID当做参数传递进来,由于有多个角色的情况,所以直接将角色ID拼接成字符串,并用逗号分隔开。

mapper接口:

List getOwnAssignedOrderNo(@Param("backendId") String backendId, @Param("role") String role);

mapper文件:

AND w.backend_id = #{backendId}

AND w.workflow_type = 'manual_check'

AND w.backend_id = #{backendId}

AND w.workflow_type = 'phone_check'

AND w.backend_id = #{backendId}

AND (w.workflow_type = 'manual_check' OR w.workflow_type = 'phone_check')

大家注意看我这里的写法,算得上是中规中矩,role参数已经明确指定了string类型,而且在if条件中,我并没有什么特殊的写法,结果却悲剧了:

Caused by: org.apache.ibatis.exceptions.PersistenceException:

### Error querying database. Cause: java.lang.NumberFormatException: For input string: "2,3"

### Cause: java.lang.NumberFormatException: For input string: "2,3"

at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)

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: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:434)

... 140 common frames omitted

Caused by: java.lang.NumberFormatException: For input string: "2,3"

at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)

at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)

at java.lang.Double.parseDouble(Double.java:538)

at org.apache.ibatis.ognl.OgnlOps.doubleValue(OgnlOps.java:242)

at org.apache.ibatis.ognl.OgnlOps.compareWithConversion(OgnlOps.java:99)

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.ASTEq.getValueBody(ASTEq.java:52)

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.CachingExecutor.query(CachingExecutor.java:81)

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.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)

at com.github.pagehelper.SqlUtil._processPage(SqlUtil.java:247)

at com.github.pagehelper.SqlUtil.processPage(SqlUtil.java:229)

at com.github.pagehelper.PageHelper.intercept(PageHelper.java:118)

at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)

at com.sun.proxy.$Proxy349.query(Unknown Source)

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)

... 146 common frames omitted

错误非常的熟悉,类型转换异常,而且定位到了我的role参数上,一开始让我很费解,难道不能用数字类型的字符串做过参数?

以为需要对mybatis做什么特殊的配置,但是后来去其他项目比对了一下,并没有什么不一样,又跑去百度了一波,看到有人提到说没有指定jdbcType导致的,但是我这个不是字段,而是在if条件中,没办法指定jdbcType。

继续查资料,看到有大佬给了一种写法,需要对if条件中的参数做toString(),写法如下:

AND w.backend_id = #{backendId}

AND w.workflow_type = 'manual_check'

AND w.backend_id = #{backendId}

AND w.workflow_type = 'phone_check'

AND w.backend_id = #{backendId}

AND (w.workflow_type = 'manual_check' OR w.workflow_type = 'phone_check')

不是我说,这种写法真的是很烦,判断条件简单还好说,如果复杂的条件,岂不是要写到吐血,遂继续百度之,终于找到了一种简单的写法:单引号和双引号调换一下

AND w.backend_id = #{backendId}

AND w.workflow_type = 'manual_check'

AND w.backend_id = #{backendId}

AND w.workflow_type = 'phone_check'

AND w.backend_id = #{backendId}

AND (w.workflow_type = 'manual_check' OR w.workflow_type = 'phone_check')

这样就舒服多了,不用每个if条件中都写toString(),而且问题也解决了!

此问题的出现,可以说完全是平时不注意细节所致,在项目中,我之前是有看到过同事这样写过,当时还纳闷儿为什么要将单双引换着用,强迫症的我甚至还差点儿手贱改了人家的代码,想要帮人家改邪归正,现在回想起来还真的是肤浅、无知~

方法总结:

1、如果在传参字段中,可以考虑追加jdbcType属性来指定数据类型;

2、如果在if条件中,用字符串比对的的地方少,可以直接在字符串后面跟一个toString()方法;

3、如果在if条件中,用字符串比对的地方多,直接将单引和双引调换位置;

综合考虑,尽量使用第三种写法,简单实用!

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐