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 ...
随机推荐
- bootstrap 模态框(modal)插件使用
今天用户登陆时,在原网页上弹出新登陆窗口,发现使用的是modal插件,记录下该插件的使用方法,手写强化下. 首先,模态框(modal)是覆盖在父窗体上的子窗体,目的是显示来自一个单独的源的内容,可以在 ...
- 基于Multiple treatment的营销评估算法
营销是发现或挖掘准消费者和众多商家需求,通过对自身商品和服务的优化和定制,进而推广.传播和销售产品,实现最大化利益的过程.例如,银行可通过免息卡或降价对处在分期意愿边缘的用户进行营销,促使其分期进而提 ...
- [BZOJ 4417][Shoi2013]超级跳马
4417: [Shoi2013]超级跳马 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 379 Solved: 230[Submit][Status ...
- C++多线程学习之(一)——并发与多线程
1 并发 计算机领域的并发指的是在单个系统里同时执行多个独立的任务,而非顺序地进行一些活动. 1.1 并发的途径 多进程并发:将应用程序分为多个独立的进程,它们在同一时刻运行,就像同时进行网页浏览和文 ...
- C++之异常捕获和处理
一.简介 在C++语言中,异常处理包括:throw表达式,try语句块,一套异常类.其中,异常类用于在throw表达式和相关的catch子句之间传递异常的具体信息.exception头文件定义了最 ...
- Week03-面向对象入门
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词,如类.对象.封装等 类 对象 封装 继承 覆盖 重载 构造函数 static public private toString f ...
- 《高级软件测试》11.14.安装和运行Jira
今日任务完成情况如下: 小段:研究Jira在Linux的安装教程 小费:尝试在Ubuntu下安装Jira 小高:查阅了关于Jira软件的介绍和安装教程,下载准备明天安装,并学习使用 小王:注册Jira ...
- 第三篇:Python字符编码
一 .了解字符编码的知识储备 1计算机基础知识 1.2文本编辑器存取文件的原理(nodepat++,Pycharm,word) #.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的 ...
- Python爬虫基本原理
爬虫基本原理 1. 什么是爬虫 请求网站并提取数据的自动化程序. 2. 爬虫基本流程 发起请求 通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待 ...
- ajax的原理解析
一.关于同步与异步的分析: 异步传输是面向字符的传输,它的单位是字符:而同步传输是面向比特的传输,它的单位是桢,它传输的时候要求接受方和发送方的时钟是保持一致的.而ajax就是采用的异步请求方式的. ...