MyBatis批量操作报错:Parameter 'xxxList' not found. Available parameters are [list]

2018-03-27 13:59:52

问题背景:

在Dao中使用MyBatis进行查询操作,参数是传的一个List:studentNameList,但是在执行查询的时候报错,具体日志如下:

Shell代码  收藏代码

  1. com.chenzhou.base.mybatis.IbatisSystemException: SqlSession operation; nested exception is org.apache.ibatis.exceptions.PersistenceException:   

  2. ### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'studentNameList' not found. Available parameters are [list]  

  3. ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'studentNameList' not found. Available parameters are [list]  

  4.     at com.chenzhou.base.mybatis.SqlSessionTemplate.wrapException(SqlSessionTemplate.java:341)  

  5.     at com.chenzhou.base.mybatis.SqlSessionTemplate.execute(SqlSessionTemplate.java:127)  

  6.     at com.chenzhou.base.mybatis.SqlSessionTemplate.execute(SqlSessionTemplate.java:106)  

  7.     at com.chenzhou.base.mybatis.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:138)  

  8.     at com.chenzhou.dao.GenericMybatisDao.count(GenericMybatisDao.java:306)  

  9.     at com.chenzhou.cds.ps.dao.impl.StudentDao.getStudentCount(StudentDao.java:42)  

  10.     at com.chenzhou.cds.ps.dao.impl.StudentDao$$FastClassByCGLIB$$8819e766.invoke(<generated>)  

  11.     at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)  

  12.     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)  

  13.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)  

  14.     at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)  

  15.     at com.chenzhou.util.LogUtil.doMethodInfo(LogUtil.java:85)  

  16.     at com.chenzhou.util.LogUtil.doDebugMethodLog(LogUtil.java:36)  

  17.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  

  18.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  

  19.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  

  20.     at java.lang.reflect.Method.invoke(Method.java:597)  

  21.     at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)  

  22.     at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)  

  23.     at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)  

  24.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)  

  25.     at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)  

  26.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)  

  27.     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)  

  28.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)  

  29.     at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)  

  30.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)  

  31.     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)  

  32.     at com.chenzhou.cds.ps.dao.impl.StudentDao$$EnhancerByCGLIB$$d4fcf513.getStudentCount(<generated>)  

  33.     at com.chenzhou.ps.dao.StudentDaoTest.testgetStudentCount(StudentDaoTest.java:44)  

  34. ……  

单元测试用例代码如下:

Java代码  收藏代码

  1. @Test  

  2. public void testgetStudentCount(){  

  3.     List<String> studentNameList = new ArrayList<String>();  

  4.     studentNameList.add("chenzhou");  

  5.     studentNameList.add("zhangsan");  

  6.     studentNameList.add("lisi");  

  7.     int count = studentDao.getStudentCount(studentNameList);  

  8.     System.out.println(count);  

  9. }  

studentDao中的getStudentCount方法代码如下:

Java代码  收藏代码

  1. public int getStudentCount(List<String> studentNameList){  

  2.     return super.count("getStudentCount", studentNameList);  

  3. }  

MyBatis mapper.xml定义如下:

Xml代码  收藏代码

  1. <!-- 查询学生数量  -->  

  2. <select id="Student.getStudentCount" parameterType="java.util.List" resultType="java.lang.Integer">  

  3.     <![CDATA[ 

  4.     SELECT 

  5.         COUNT(*) 

  6.     FROM 

  7.         t_student WHERE 1=1  

  8.     ]]>  

  9.     <if test="studentNameList != null">  

  10.         AND student_name in  

  11.         <foreach collection="studentNameList" item="item" open="(" separator="," close=")">  

  12.             #{item}   

  13.         </foreach>  

  14.     </if>  

  15. </select>  

根据报错日志分析,是MyBatis在解析xml时找不到其中声明的studentNameList,但是在Dao中明明传的参数就是studentNameList,怎么会报错呢?

查询了一下MyBatis官方的说明文档,终于找到了原因,在http://mybatis.github.io/mybatis-3/zh/dynamic-sql.html#foreach里有一段说明:

写道

注意 你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时 候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。

因为我传的参数只有一个,而且传入的是一个List集合,所以mybatis会自动封装成Map<"list",studentNameList>。在解析的时候会通过“list”作为Map的key值去寻找。但是我在xml中却声明成studentNameList了,所以自然会报错找不到。

 

解决办法:

第一种就是修改mapper.xml中foreach标签内容,把studentNameList修改为list

Xml代码  收藏代码

  1. <if test="list != null">  

  2.     AND student_name in  

  3.     <foreach collection="list" item="item" open="(" separator="," close=")">  

  4.         #{item}   

  5.     </foreach>  

  6. </if>  

不过这种方式我个人不太建议,因为以后如果要扩展该方法,增加集合参数的时候,还得修改xml中的内容。

 

第二种方式,修改dao中的参数传入方式,手动封装成map,然后把map当参数传进去

Dao方法修改为:

Java代码  收藏代码

  1. public int getStudentCount(List<String> studentNameList){  

  2.     //把参数手动封装在Map中  

  3.     Map<String, Object> map = new HashMap<String, Object>();  

  4.     map.put("studentNameList", studentNameList);  

  5.     return super.count("getStudentCount", map);  

  6. }  

然后修改mapper.xml中的parameterType类型为Map

Xml代码  收藏代码

  1. <!--注意下面的parameterType类型必须修改为Map类型,foreach中引用的List名称不用改变-->  

  2. <select id="Student.getStudentCount" parameterType="java.util.Map" resultType="java.lang.Integer">  

  3.     <![CDATA[ 

  4.     SELECT 

  5.         COUNT(*) 

  6.     FROM 

  7.         t_student WHERE 1=1  

  8.     ]]>  

  9.     <if test="studentNameList != null">  

  10.         AND student_name in  

  11.         <foreach collection="studentNameList" item="item" open="(" separator="," close=")">  

  12.             #{item}   

  13.         </foreach>  

  14.     </if>  

  15. </select>  

修改完后,重新执行了一下测试用例,测试通过。

  • 2019-03-15 15:32:09

    内网打洞以及代码实现

    假设内网的多个ip或者同一ip的不同port,都要访问同一个(外网ip:port)。对NAT来说,从外网接收的包它的(srcIp:srcPort)==(serverIp,serverPort),它的dstIp==natIp,所以NAT只能用dstPort来决定把这个包转发给哪一个(内网Ip:port)

  • 2019-03-15 15:33:08

    Xshell不能按退格、删除键的解决方案

    在使用xshell时,由于每个服务器不同,一些无法使用Backspace键向后删除字符。针对这个问题,本文为大家解答下退格键无法识别如何设置?

  • 2019-03-15 15:49:28

    win10远程桌面连接不上解决方法

    有朋友就感叹电脑的世界真的是很神奇,可以将整个世界连接在一起。如果别人想要摆弄你的电脑,即使不在一个地方也可以利用远程桌面来控制。而这就是所谓的远程控制操作了,大部分人都知道它的作用,不过这也不排除会遇到一些突发情况的时候,例如win10远程桌面连接不上,这该怎么去解决呢?为此,小编给大家带来了解决的图文操作。

  • 2019-03-15 16:49:18

    Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”怎么办

     家庭组是家庭网络上可以共享文件和打印机的一组计算机,可以方便用户们共享文件或者视频等,可是最近有win7纯净版系统用户却发现无法进入家庭组,提示“您的系统管理员不允许访问家庭组”,该怎么办呢?现在给大家分享一下Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”的解决方法。

  • 2019-03-17 22:19:28

    动态更新Toolbar Menu以及Menu中同时显示文字和图标

    我们经常会有这样的需求,在切换Fragment或者点击某个按钮后动态更新Toolbar上Menu项.但是onCreateOptionsMenu方法只在创建Activity的时候调用一次,以后就不再调用了,所以就不能在onCreateOptionsMenu中做处理了。 不过系统提供了另外的一个方法onPrepa

  • 2019-03-26 19:25:01

    Android studio 打包后安装闪退 Fatal Signal 6(SIGABRT)...

    项目上线前打包安装后闪退,查了很多原因,比如混淆文件的内容,第三方库不加入混淆等等,均未成功,后来关闭混淆打包后运行成功,原因可能是依赖工程中的库文件不能被混淆,关闭本工程混淆开关后,依赖工程的混淆开关也要关闭,关闭混淆后如果怕被反编译,可使用百度开发平台的app加固,加固的同时还能使用多渠道打包工具。

  • 2019-03-26 19:29:05

    Android NDK开发Crash错误定位

     在Android开发中,程序Crash分三种情况:未捕获的异常、ANR(Application Not Responding)和闪退(NDK引发错误)。其中未捕获的异常根据logcat打印的堆栈信息很容易定位错误。ANR错误也好查,Android规定,应用与用户进行交互时,如果5秒内没有响应用户的操作,则会引发ANR错误,并弹出一个系统提示框,让用户选择继续等待或立即关闭程序。并会在/data/anr目录下生成一个traces.txt文件,记录系统产生anr异常的堆栈和线程信息。如果是闪退,这问题比较难查, --------------------- 作者:xyang0917 来源:CSDN 原文:https://blog.csdn.net/xyang81/article/details/42319789 版权声明:本文为博主原创文章,转载请附上博文链接!