【问题标题】:Hibernate throwing a ConcurrentModificationExceptionHibernate 抛出 ConcurrentModificationException
【发布时间】:2012-07-18 04:43:40
【问题描述】:

我正在为我一直在处理的 持久层编写一些测试,但遇到了一个我无法处理的异常,即 ConcurrentModificationException em> 发生在 org.hibernate.mapping.Table.cleanseUniqueKeyMap(Table.java:291)
原来是这行代码:

final Map.Entry<String,UniqueKey> uniqueKeyEntry = uniqueKeyEntries.next();

在做了一些研究之后,我发现异常是由一个线程在这个线程迭代它时修改这个集合引起的。话虽如此,我觉得我所做的一切都没有导致这种情况发生,有什么关于故障排除的建议吗?

顺便说一句,我使用hibernate 4.1.5。 Idk 是否可以解决任何问题。这是我的测试:

@Test
public void testCreateMobsterUser() {
   try {            
       final MobsterUserDAO test = new MobsterUserDAO(); //throws exception
       //does stuff w/ return value...

如您所见,我们尝试初始化 dao 让我们看看代码:

public MobsterUserDAO() {
    super(MobsterUser.class);
}

好吧,这并没有向我们展示太多,所以让我们看看通用 dao 构造函数,看看你是否发现了那里的问题。

public MobsterBaseHibernateDAO(final Class<T> clazz) {
    this.clazz = clazz;
    //This next line is where the exception is actually occuring
    final EntityManagerFactory factory = Persistence.createEntityManagerFactory("mobsterdb");
    this.manager = (HibernateEntityManager) factory.createEntityManager();
}

现在我不确定 Persistance.createEntityManagerFactory 是哪种兔子洞,但这是我在异常发生之前执行的代码的最后一行。

【问题讨论】:

标签: java hibernate exception


【解决方案1】:

当您在 for-each 循环中迭代集合并在其他地方更改集合时,会发生并发修改。一种常见的解决方案是使用 Iterator 而不是 for-each 循环。或者将您的收藏放在synchronized 块中。

到处都有资源:

Avoiding ConcurrentModificationException,上面写着:

  1. 您可以将列表转换为数组,然后对数组进行迭代。这种方法适用于中小型列表,但如果列表很大,则会对性能产生很大影响。

  2. 您可以在迭代时锁定列表,方法是将其放入同步块中。不推荐使用这种方法,因为它会失去多线程的好处。

  3. 如果您使用的是 JDK1.5 或更高版本,则可以使用 ConcurrentHashMap 和 CopyOnWriteArrayList 类。这是推荐的方法。

还有:

Concurrent Modification exception
How to debug ConcurrentModificationException?

【讨论】:

  • 我明白了,但我想重复一下在休眠中发生异常的点,即不是我编写的代码。我的应用程序中什至没有多个线程(至少不是我做的)。它必须是由我真正知道的休眠配置方式引起的。如果我发布打印的堆栈跟踪会有帮助。
  • 他们甚至不是同一个例外。
【解决方案2】:

由于在 Hibernate 的内部管理过程​​中这似乎是一个例外,我认为这是一个错误。在 Google 上快速搜索确实会显示 a recently reported JIRA

提出了一项决议,但不知道何时发布。

希望这会有所帮助!

【讨论】:

  • 我很感激。 JIRA 上的堆栈跟踪看起来与我的几乎相同。
  • 至于我的问题...我应该下载源将地图更改为并发地图并重新编译?
  • 我希望有人尝试hibernate.onjira.com/browse/HHH-7456 中所述的解决方案,但是是的,获取源代码,进行更改并构建。它不像我们在Hibernate构建中使用一些代码生成工具那样简单地编译,只需按照自述文件中的说明进行操作
  • 相反,如果您向 Jira 添加了一个 simplified 测试用例,它也可以工作......
  • @SteveEbersole 我需要提供什么?实体实现(作为私有类)、DAO(另一个私有)和我的 persistence.xml 文件?这是足够还是过度?
【解决方案3】:

发生这种情况是因为您的循环遍历了一个集合,然后在循环内部的某个地方,您更改了您正在迭代的集合,然后您尝试恢复循环,就好像什么都没有改变一样。

我也遇到过同样的事情:

for(UserJPA jpa : jpaList){
    if(jpa satisfies a condition){
        jpaList.remove(jpa);
    }
}

问题是您无法修改正在迭代的列表。在我的情况下,我选择的解决方案是制作一个新列表,即原始列表的副本,在修改原始列表的同时对其进行迭代:

List<UserJPA> iterationList = new ArrayList<UserJPA>(jpaList);
for(UserJPA jpa : iterationList){
    if(jpa satisfies a condition){
        jpaList.remove(jpa);
    }
}

希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2013-02-12
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2017-10-18
    • 1970-01-01
    相关资源
    最近更新 更多