org.apache.commons.lang3.tuple.Pair 作为更新参数,XML 中的 Sql 取不到值、报错
项目用的 Mybatis,今天改一个需求,落地实现是批量更新,且只需要根据主键(id)来更新一个字段(name)。
于是,没有犹豫,像下面这样设计了数据结构:
- 既然是批量更新,那外层肯定是 List
- List 中每个元素,只包含 id & name,于是,选择了用 org.apache.commons.lang3.tuple.Pair 来封装数据(就是不想自己再写一个 DO 或者 VO 或者 MO)
- 最终的数据结构是:List<Pair<Integer, String>>
XML 中的 Sql 语句,很简单,如下:
<update id="updateByApacheCommonsPair">
<foreach collection="list" separator=";" item="x">
UPDATE employee SET name = #{x.right} WHERE id = #{x.left}
</foreach>
</update>
提示:XML 中的 Sql 引入了一个名为 x 的变量(后面会用到)
一切顺利,但测试时,报错如下:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'right' in 'class java.lang.String'
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: UPDATE employee SET name = ? WHERE id = ?
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'right' in 'class java.lang.String' at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:200)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
at com.sun.proxy.$Proxy4.updateByApacheCommonsPair(Unknown Source)
at com.atguigu.mybatis.test.MyBatisTest.testUpdateByApacheCommonsPair(MyBatisTest.java:42)
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:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
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.reflection.ReflectionException: There is no getter for property named 'right' in 'class java.lang.String'
at org.apache.ibatis.reflection.Reflector.getGetInvoker(Reflector.java:409)
at org.apache.ibatis.reflection.MetaClass.getGetInvoker(MetaClass.java:164)
at org.apache.ibatis.reflection.wrapper.BeanWrapper.getBeanProperty(BeanWrapper.java:162)
at org.apache.ibatis.reflection.wrapper.BeanWrapper.get(BeanWrapper.java:49)
at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:119)
at org.apache.ibatis.mapping.BoundSql.getAdditionalParameter(BoundSql.java:75)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:72)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:93)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
... 26 more
问题已经出了,那就解决吧。
报错中的提示信息还是比较容易阅读:java.lang.String 类中没有 right 字段的 getter 方法
奇怪,怎么会报这样的错:
- java.lang.String 类中确实没有 right 字段
- right 字段是 Pair 中的(因为我用的就是 Pair)
- 它们两者搅在一起了?
猜测了一些原因,不过都不对,最后,没办法了,只有自己写了一个 CYHPair (也是一个包含两个字段的POJO)来实现,结果,又是可以的。
所以,接下来就有思路了:比较自己写的 CYHPair 和 org.apache.commons.lang3.tuple.Pair 在哪些地方有所不同。
最后发现(实验了很长时间),一个比较大的不同之处在于,org.apache.commons.lang3.tuple.Pair 实现了 Map.Entry 接口(自己写的 CYHPair 没有),这会不会有影响?
最终的结论证明:就是因为实现了 Map.Entry 所以导致了后面取不到值,所以报错如上。
可是,这又是为什么呢?于是,继续源码调试。
Demo 代码地址:https://github.com/cyhbyw/mybatis_atguigu
Demo 工程名称:MyBatis_CYH_test_MapEntry
第一:先来调试正常的Case(即基于 CYHPair 来做更新操作的)
01. 可以看到,Line#73 判断了是否属于 Map.Entry;由于我的 CYHPair 没有实现它,所以,代码进入 else 部分;注意这里的第二个参数是 o 本身,而 o 是 CYHPair 的一个实例
02. 从 Line#102 可以看到,将 o 这个 CYHPair 对象绑定给了 x (提示:x 是 Sql 中的变量)
简单结论:x 这个变量是 CYHPair 类型的!
第二步:接下来调试不正常的(即基于 org.apache.commons.lang3.tuple.Pair 来做更新操作的)
01. 还是 Line#73 行的判断,不过这一次,判断成立,于是,代码走到 Line#77 行;注意第二个参数是 mapEntry.getValue(),而这个值是字符串 ApacheCommonsPair;
02. 绑定的时候,就将 ApacheCommonsPair 这个字符串值绑定给了变量 x
03. 所以现在容易理解它为什么会报错 “java.lang.String 类中没有 right 字段的 getter 方法” 了,因为就是 02 步中将字符串 ApacheCommonsPair 绑定给了 x 呀,那就肯定没有 right 字段也没有对应的 getter 方法啦~~
org.apache.commons.lang3.tuple.Pair 作为更新参数,XML 中的 Sql 取不到值、报错的更多相关文章
- 【java】org.apache.commons.lang3功能示例
org.apache.commons.lang3功能示例 package com.simple.test; import java.util.Date; import java.util.Iterat ...
- org.apache.commons.lang3.ArrayUtils 学习笔记
package com.nihaorz.model; /** * @作者 王睿 * @时间 2016-5-17 上午10:05:17 * */ public class Person { privat ...
- spring异常记录-----java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
今天在练习怎样SSH中进行单元測试的时候出现下列异常: SEVERE: Exception starting filter Struts2 java.lang.NoClassDefFoundError ...
- Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
1.错误叙述性说明 2014-7-10 23:12:23 org.apache.catalina.core.StandardContext filterStart 严重: Exception star ...
- org.apache.commons.lang3 的随机数生成
apache org.apache.commons.lang3 的随机数生成工具,方便使用. String a12 = RandomStringUtils.random(4, "012345 ...
- NoClassDefFoundError: org/apache/commons/lang3/StringUtils
出错信息: 2014-2-5 21:38:05 org.apache.catalina.core.StandardContext filterStart严重: Exception starting f ...
- Hadoop java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
.jar 学习好友推荐案例的时候,提交运行时报错找不到StringUtils java.lang.ClassNotFoundException: org.apache.commons.lang3.St ...
- 20190313 org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法
org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法 public boolean equals(Object obj) { if (obj == ...
- struts2中的错误--java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
2013-4-7 10:13:56 org.apache.catalina.startup.HostConfig checkResources 信息: Reloading context [/chap ...
随机推荐
- 【备忘】Idea的那些事
说到Java的IDE,似乎eclipse和Idea是目前的主流.然而,OO的课程组却一直在推荐使用eclipse,于是很多人就这样错过了Idea这样强大的IDE工具.本文将会对于Idea和Idea的一 ...
- 简单hdfs相关操作命令
HDFS常用操作命令 启动hdfs #start-all.sh 查看hdfs的配置文件 #cat hdfs-site.sh #hadoop fs -put /soft/jdk / #HDFS上传文件命 ...
- 听翁恺老师mooc笔记(3)--指针的定义
在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...
- 【iOS】OC-AFNetworking 2.0 跟踪文件上传进度
我是较新的 AFNetworking 2.0.使用下面的代码片段,我已经能够成功地将一张照片上传到我的 url.我想要跟踪的增量上载进度,但我找不到这样做 2.0 版的示例.我的应用程序是 iOS 7 ...
- OO第一次作业总结
OO第一次学习总结 1.第一次作业:多项式加法 从未接触过java的我,在从输入输出开始学了几天后,按照C语言的思路,写出了一个与面向过程极其接近的程序. 在这个程序中,存在两个类:一个是Comput ...
- php的控制器链
控制器之间协同工作就形成了控制器链· 比如在一个控制器的方法中,创建另外一个·控制器,创建对象,然后调用第二个控制器方法,那么在第一个控制器分配给视图的变量,在 第二个控制器的方法中对应的视图也是可以 ...
- 搭建一个web服务下载HDFS的文件
需求描述 为了能方便快速的获取HDFS中的文件,简单的搭建一个web服务提供下载很方便快速,而且在web服务器端不留临时文件,只做stream中转,效率相当高! 使用的框架是SpringMVC+HDF ...
- jquery 实时监听输入框值变化方法
$('.offers-number').bind('input propertychange', function (a, b) { var value = $(this).val() if (!va ...
- hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(1)安装jdk
一.文件准备 下载jdk-8u131-linux-x64.tar.gz 二.工具准备 2.1 Xshell 2.2 Xftp 三.操作步骤 3.1 解压文件: $ tar zxvf jdk-8u131 ...
- Spring Security入门(3-4)Spring Security 异常处理、异常传递和异常获取