You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迭代Hibernate子集合触发save后抛出ConcurrentModificationException如何解决?

问题原因

你遇到的ConcurrentModificationException本质是Hibernate持久化集合的特性导致的:

  • Parent的child集合是Hibernate的AbstractPersistentCollection代理对象,它会跟踪集合的结构变化。
  • 你在遍历这个集合的forEach循环里,同步触发了事件监听器,监听器中的childRepository.save(child)会触发Hibernate持久化上下文的刷新,间接修改了这个集合的内部状态(比如更新集合版本、重新加载元素)。
  • 集合的迭代器在遍历下一个元素时,检测到集合结构和迭代启动时不一致,就抛出了并发修改异常。
解决方案

方案1:将持久化集合转为普通Java集合遍历

把Hibernate代理的集合转成普通的ArrayList/HashSet,这样遍历的是脱离Hibernate控制的独立集合,后续原持久化集合的修改不会影响当前迭代:

// 先复制为普通List,避免迭代Hibernate的持久化集合
new ArrayList<>(parent.getChild()).forEach(child -> {
    if (child.getStatus().equals("PENDING")) {
        applicationEventPublisher.publishEvent(new NewEvent(child));
        publishLifeCycleEvent(deal);
    }
});

这个方案简单直接,不需要额外配置,适合需要同步执行监听器逻辑的场景。

方案2:异步执行事件监听器

让事件监听器在独立线程中执行,这样遍历过程不会等待监听器完成,也就不会在迭代时触发集合的修改:

  1. 先在Spring配置类上开启异步支持:
@EnableAsync
@Configuration
public class AsyncConfig {
    // 可根据需求自定义线程池配置
}
  1. 给事件监听器添加@Async注解:
@Async
@EventListener
public void saveChildEvent(NewEvent childEvent) {
    Child child = childEvent.getChild();
    //...do processing
    childRepository.save(child);
}

注意:异步场景下需要确保事务正确性,可给监听器方法添加@Transactional注解,避免事务上下文丢失。

注意事项
  • Hibernate持久化集合与Session绑定,迭代过程中尽量避免触发集合的结构修改或刷新操作。
  • 如果使用异步方案,要考虑线程安全和事务边界问题,比如避免在异步方法中操作同一个Session实例。

内容的提问来源于stack exchange,提问作者Lolly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:40:35