Hibernate抛出一个ConcurrentModificationException

时间:2012-07-18 04:43:40

标签: java hibernate exception

我正在为 persistance layer 编写一些测试我一直在努力,而且我遇到了一个例外,我遇到了麻烦,一个 ConcurrentModificationException 它发生在 org.hibernate.mapping.Table.cleanseUniqueKeyMap(Table.java:291)
结果是这行代码:

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

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

BTW,我正在使用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是什么样的兔子洞,但这是我的代码在异常发生之前执行的最后一行。

3 个答案:

答案 0 :(得分:4)

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

有关于它的资源:

Avoiding ConcurrentModificationException,它说:

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

  2. 您可以通过将列表放在同步块中来锁定列表。不建议采用这种方法,因为它会停止多线程的好处。

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

  4. 此外:

    Concurrent Modification exception
    How to debug ConcurrentModificationException?

答案 1 :(得分:2)

由于Hibernate在内部管理期间似乎是一个例外,我认为它是一个错误。在Google上进行快速搜索会显示a recently reported JIRA

提出了一项决议,但不知道什么时候会发布。

希望这有帮助!

答案 2 :(得分: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);
    }
}

希望有所帮助。