mybatis foreach多次遍历问题:Error evaluating expression ‘’. Return value () was not iterable.

本文探讨了在使用 MyBatis 的 foreach 循环时遇到的问题,特别是当循环变量名称重复导致的错误,并提供了修改建议。

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

mybatis foreach多次遍历问题:

使用MyBatis foreach循环的时候出现了个问题,第一次循环使用的变量  第二次再次循环使用的时候  出现了报错  


  1. Caused by: org.apache.ibatis.builder.BuilderException: Error evaluating expression ‘status’.  Return value (1) was not iterable.  
  2.     at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateIterable(ExpressionEvaluator.java:65)  
  3.     at org.apache.ibatis.scripting.xmltags.ForEachSqlNode.apply(ForEachSqlNode.java:55)  
  4.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  5.     at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35)  
  6.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  7.     at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55)  
  8.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  9.     at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35)  
  10.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  11.     at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55)  
  12.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  13.     at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35)  
  14.     at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)  
  15.     at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41)  
  16.     at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292)  
  17.     at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)  
  18.     at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)  
  19.     at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)  
  20.     at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source)  
  21.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  
  22.     at java.lang.reflect.Method.invoke(Method.java:606)  
  23.     at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:434)  
  24.     … 82 more  
Caused by: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'status'.  Return value (1) was not iterable.
    at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateIterable(ExpressionEvaluator.java:65)
    at org.apache.ibatis.scripting.xmltags.ForEachSqlNode.apply(ForEachSqlNode.java:55)
    at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33)
    at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:35)
    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.IfSqlNode.apply(IfSqlNode.java:35)
    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.IfSqlNode.apply(IfSqlNode.java:35)
    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 org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
    at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source)
    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)
    ... 82 more

看到这个问题 大概能想到的就是值 被改变了  我就纳闷了一会  我在代码都没有调用啊。然后我去查了下资料,看了下源码调试了一下


这是我本身写的foreach循环


源码在  ExpressionEvaluator.java中的evaluateIterable方法:

此时我foreach 要循环的collection 是 status 看到的值是一个数组

到这里是第一个foreach 是完全没有任何问题的,第二个foreach 是直接copy第一个foreach的

然后调试发现多跑了一个status出来

此时的status 既不是一个数组也不是一个集合   所以抛出了异常

MyBatis底层的实现应该是foreach 里面的 item 作为每次循环的一个标记变量,我这里item 和  collection都重复了就导致了这个问题

解决办法就是item 换一个变量名  ,尽量不要和collection 变量名重复就行了


<think>好的,我现在要解决用户在使用MyBatis进行批量删除时遇到的错误:“Error evaluating expression 'ids'”以及“BuilderException: ids not iterable”。首先,我需要了解这个问题的根本原因。根据用户提供的信息,错误提示指出'ids'不可迭代,这说明MyBatis在处理传入的参数时,期望一个可迭代的对象(比如List或数组),但实际传入的可能不符合要求。 首先,我需要回忆MyBatis中如何处理动态SQL,特别是在使用`<foreach>`标签时。`<foreach>`标签通常用于遍历集合,生成相应的SQL语句部分。例如,在批量删除时,可能会用到类似`DELETE FROM table WHERE id IN <foreach collection="ids" ...>`的结构。这里的`collection`属性需要指定一个可迭代的参数名称。 接下来,用户的问题可能出现在参数的传递方式上。MyBatis的Mapper接口方法参数如果是单个参数,默认情况下可以直接通过参数名引用。但如果有多个参数,需要使用`@Param`注解来指定名称。如果用户传入的参数是一个List或数组,但在Mapper方法中没有正确使用`@Param`注解,或者在XML中引用的名称不一致,就会导致MyBatis无法找到对应的可迭代集合,从而抛出错误。 另外,用户可能没有正确封装参数。例如,如果参数是一个对象,但对象中的属性名称与XML中引用的名称不匹配,或者直接传递了一个基本类型的数组而没有包装成Map或对象,也会导致这个问题。 接下来,我需要考虑可能的解决方案。首先,检查Mapper接口方法的参数是否正确使用了`@Param`注解,确保在XML中引用的名称与之一致。例如,如果方法参数是`@Param("ids") List<Integer> ids`,那么在XML中的`collection`属性应该是“ids”。如果用户没有使用注解,而直接传递了一个List,那么在旧版本的MyBatis中可能需要使用默认的“list”或“array”作为集合名称,但这容易出错,建议使用`@Param`明确指定。 其次,确认传入的参数确实是一个可迭代的对象。例如,在调用Mapper方法时,是否传递了一个List或数组,而不是其他类型的对象。如果传入的是一个用Map包装的参数,需要确保Map中的键与XML中引用的名称一致。 另外,检查XML中的SQL语句是否正确。例如,`<foreach>`标签的`collection`属性是否正确,item、open、close、separator等属性是否配置正确。例如,正确的写法应该是: ```xml <delete id="batchDelete"> DELETE FROM table WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </delete> ``` 此外,还需要注意参数的类型。如果参数是放在一个对象中的,比如参数对象有一个名为`ids`的属性,那么在XML中应该使用`collection="ids"`,并且确保传入的参数对象中包含这个属性。 可能用户在使用MyBatis的注解方式时,比如使用`@DeleteProvider`,参数传递的方式可能有所不同,需要确认生成的动态SQL是否正确处理了集合参数。 还有一个可能性是MyBatis的版本问题。旧版本的MyBatis在处理某些集合类型时可能存在兼容性问题,建议用户检查版本,并考虑升级到最新版本。 最后,用户可能需要检查日志或异常堆栈,确认具体的错误位置,例如是解析XML时的错误,还是运行时参数传递的错误。通过调试或打印传入参数的类型和结构,可以更快地定位问题。 总结来说,解决方案的步骤可能包括: 1. 确认Mapper接口方法的参数是否正确使用`@Param`注解。 2. 检查XML中的`<foreach>`标签的`collection`属性是否与参数名称一致。 3. 确保传入的参数是一个可迭代的集合类型。 4. 验证SQL语句的正确性,包括括号和分隔符的配置。 5. 检查参数是否被正确封装在对象或Map中。 6. 必要时升级MyBatis版本以避免已知的兼容性问题。 接下来,我需要将这些思考整理成结构化的步骤,用中文清晰地向用户解释问题原因和解决方法,同时生成相关的问题供用户进一步参考。</think>### 解决MyBatis批量删除报错"Error evaluating expression 'ids'"的步骤 #### 问题原因分析 1. **参数未正确标记** Mapper接口方法未使用`@Param("ids")`明确标注参数名称,导致XML中的`collection="ids"`无法识别参数来源[^1]。 2. **参数类型不可迭代** 传入的参数不是`List`、`数组`或可迭代对象(如直接传递了单个数值而非集合)。 3. **XML配置错误** `<foreach>`标签的`collection`属性值错误,或参数未包裹在对象中(如直接使用基本类型数组未封装)。 --- #### 解决方案 ##### 方法1:使用`@Param`明确参数名 ```java // Mapper接口方法 void batchDelete(@Param("ids") List<Long> ids); ``` ```xml <!-- XML配置 --> <delete id="batchDelete"> DELETE FROM table WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </delete> ``` *关键点*:`@Param("ids")`与`collection="ids"`必须严格对应。 ##### 方法2:直接传递集合类型 如果参数仅有一个且为`List`或数组: ```xml <foreach collection="list" ...> <!-- 参数为List时默认名称为list --> 或 <foreach collection="array" ...> <!-- 参数为数组时默认名称为array --> ``` ##### 方法3:参数包裹在对象中 ```java // 参数对象 public class DeleteParam { private List<Long> ids; // getter & setter } ``` ```xml <foreach collection="ids" ...> <!-- 引用对象属性名 --> ``` --- #### 验证示例 ```java // 调用示例(正确传递List) List<Long> idList = Arrays.asList(1L, 2L, 3L); mapper.batchDelete(idList); ``` --- #### 错误排查 1. **检查日志** 查看MyBatis生成的SQL日志,确认`IN`语句是否生成正确,如: ```sql DELETE FROM table WHERE id IN ( ? , ? , ? ) ``` 若未生成多个占位符,说明集合未被正确解析。 2. **参数类型检查** 使用调试工具确认传入参数的实际类型是否为`java.util.List`或其实现类。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值