并行流操作引发MyBatis foreach生成异常SQL问题排查
并行流操作HashSet导致生成不完整SQL的原因及修复
问题根源:HashSet是非线程安全的容器,在
parallelStream().forEach()中多线程并发调用add()方法时,会造成内部数据结构损坏(比如哈希表冲突、size计数异常)。哪怕原list非空,最终的ids集合可能出现两种情况:要么元素全部丢失导致集合为空,要么集合的size显示非空但实际没有可遍历的元素。后者会绕过ObjectUtils.isEmpty(ids)的判断,传给MyBatis后,<foreach>遍历不到元素,就生成了select name from user where id in这种不完整的SQL。修复方案:并行流中必须使用线程安全的方式收集结果,用
Collectors.toSet()替代手动操作HashSet:
public List<String> queryByIds() { Set<Long> ids = list.parallelStream() .map(obj -> obj.id) .collect(Collectors.toSet()); if (ObjectUtils.isEmpty(ids)){ return Collections.emptyList(); } return mapper.queryByIds(ids); }
Collectors.toSet()在并行流场景下会自动使用线程安全的收集容器,避免并发修改导致的数据异常,保证ids集合能正确收集所有元素。
- 补充说明:原代码里
ids.add(obj.id)末尾缺了分号,这是语法错误,应该是输入时的笔误。核心问题还是非线程安全容器在并行流中的误用。
内容的提问来源于stack exchange,提问作者senz
相关产品推荐
相关产品推荐

