1

我正在为我一直在研究的持久性层编写一些测试,并且遇到了一个我无法处理的异常,发生在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 是哪种兔子洞,但这是我在异常发生之前执行的代码的最后一行。

4

3 回答 3

3

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

到处都有资源:

避免 ConcurrentModificationException,它说:

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

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

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

还:

ConcurrentModificationException
如何调试 ConcurrentModificationException?

于 2012-07-18T04:46:16.657 回答
2

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

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

希望这可以帮助!

于 2012-07-18T06:19:27.210 回答
0

发生这种情况是因为您的循环通过一个集合,然后在循环内部的某个位置,您更改了您正在迭代的集合,并且您尝试恢复循环,就好像没有任何变化一样。

我也有同样的事情发生在我身上:

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);
    }
}

希望有帮助。

于 2016-11-02T12:51:52.583 回答