mybatis的forEach标签中遍历Map的正确使用方式

mybatis的forEach标签中遍历Map的正确使用方式

问题背景

最近写代码的时候遇到了想用forEach遍历Map的场景,然后按照惯性思维进行编写代码,如下

    <foreach item="entry" collection="map.entrySet()" separator=" OR ">
        (name = #{entry.key} AND age = #{entry.value})
    </foreach>

报错There is no getter for property 'key' in 'java.lang.String' 这个应该是jdk8版本,在jdk17版本则会报错一个关于什么BASE包无法访问的问题,与这个报错类似,时间稍微有点久,就不详细贴了。

解决方案

在网上搜索了一些列的使用方式,包括上面的错误写法,并且上面的错误写法非常的多,所以我在这里用源码对正确的方式进行证明,之前直接用了,现在有时间看一下源码,希望大家后续用到Map遍历的时候,能够少踩坑,使用时也能知道为啥是这样用的,正确的使用方式如下:

<foreach item="value" index="key" collection="map.entrySet()">
    <!-- 正确:直接通过 key 和 value 访问 -->
    (name = #{key} AND age = #{value})
</foreach>

如果将map.entrySet()作为collection,则mybatis的处理为,将key绑定为index,将value绑定为item,而不是正常的index为数字,item为迭代器中的元素,下面是源码证明,源码版本从3.5.0开始就已经是这样了,再之前的版本就没有进行验证了,大家可以自行搜索自己代码中的类ForEachSqlNode.class进行源码查看。

  @Override
  public boolean apply(DynamicContext context) {
    Map<String, Object> bindings = context.getBindings();
    final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings,
        Optional.ofNullable(nullable).orElseGet(configuration::isNullableOnForEach));
    if (iterable == null || !iterable.iterator().hasNext()) {
      return true;
    }
    boolean first = true;
    applyOpen(context);
    int i = 0;
    for (Object o : iterable) {
      DynamicContext oldContext = context;
      if (first || separator == null) {
        context = new PrefixedContext(context, "");
      } else {
        context = new PrefixedContext(context, separator);
      }
      int uniqueNumber = context.getUniqueNumber();
      // 这里,进行判断如果迭代器中的元素是继承自Map.Entry则走单独的逻辑
      if (o instanceof Map.Entry) {
        @SuppressWarnings("unchecked")
        Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;
        // 将mapEntry.getKey()和index绑定
        applyIndex(context, mapEntry.getKey(), uniqueNumber);
        // 将mapEntry.getValue()和item绑定
        applyItem(context, mapEntry.getValue(), uniqueNumber);
      } else {
        applyIndex(context, i, uniqueNumber);
        applyItem(context, o, uniqueNumber);
      }
      contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));
      if (first) {
        first = !((PrefixedContext) context).isPrefixApplied();
      }
      context = oldContext;
      i++;
    }
    applyClose(context);
    context.getBindings().remove(item);
    context.getBindings().remove(index);
    return true;
  }
### 回答1: Mybatis中的foreach循环可以用于遍历一个List或者数组,也可以用于遍历一个Map。如果要遍历一个Map,需要在foreach标签中指定collection属性为Map的keySet()方法,同时指定item属性为Map中的key值,index属性为Map中的value值。例如: ``` <select id="selectByMap" parameterType="map" resultType="User"> SELECT * FROM user WHERE id IN <foreach collection="ids" item="id" index="index" open="(" separator="," close=")"> #{id} </foreach> </select> ``` 其中,ids是一个Map类型的参数,key为String类型,value为Integer类型。在foreach标签中,指定了collection属性为ids.keySet(),item属性为key,index属性为value,这样就可以遍历Map中的key值了。 ### 回答2: mybatis是一个Java持久化框架,它提供了一个非常方便的功能,即foreach循环mapMybatis中的foreach循环map功能非常重要,因为它能够简化我们的SQL语句,提高我们的开发效率。 在mybatis中,我们可以使用foreach来循环一个mapmap是一种非常常见的数据结构,它是由一组键值对组成的。我们可以用foreach来循环map中的键或值,也可以同时循环map中的键和值。 使用mybatisforeach循环map,需要我们定义一个map标签,然后使用foreach标签来循环map中的键和值,我们还可以使用index变量来获取当前循环的索引。 除了循环map中的键和值,我们还可以在foreach使用if语句来过滤map中的数据,这样我们可以更精确地获取我们所需的数据。 使用mybatis中的foreach循环map要注意一些细节,比如说循环map的键和值时要使用entry标签,而不能使用key或value标签。此外,我们还需要通过指定collection属性来指定我们要循环的map。 总之,mybatis中的foreach循环map功能非常强大,它可以让开发者更高效地编写SQL语句,提高开发效率。使用foreach循环map需要注意一些细节,但只要掌握了相关的知识,就可以轻松地完成各种复杂的开发任务。 ### 回答3: MyBatis是一款面向Java语言的持久层框架,它提供了许多方便的实现数据库操作的方式。在MyBatis中,foreach语句是一种非常强大的循环语句,可以用来遍历集合或数组,并将其转换成SQL语句的一部分。在MyBatis中,可以使用foreach循环遍历一个Map对象。 在使用foreach循环遍历Map时,需要在SQL语句中使用#{}占位符,并在foreach标签中指定Map的key和value变量名。具体实现方式如下: 使用Map进行数据查询: ``` <select id="getUserListByMap" parameterType="java.util.Map" resultType="com.example.User"> SELECT * FROM user WHERE <foreach collection="param.keySet()" index="key" item="item" open="" close="" separator="AND"> ${key} = #{item} </foreach> </select> ``` 通过上面这段代码可以看到,在SQL语句中使用了#{}占位符,并使用foreach标签遍历Map对象。其中,collection属性用于指定要遍历Map对象,item属性表示Map中的value值,index属性表示Map中的key值。 在以上SQL语句中,遍历Map对象得到的结果类似于: SELECT * FROM user WHERE age = 18 AND name = 'Bob' AND sex = 'male'; 这条语句是根据输入的Map对象中的键值对动态生成的,可以根据不同的需求进行调整。 总之,使用foreach循环遍历Map对象是MyBatis中一种十分常见的操作方式,能够大大提升查询的效率,并且极大地降低了程序开发的难度。需要注意的是,在使用foreach循环时,需要格外注意SQL语句的正确性,并避免出现语法错误。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值