简体   繁体   中英

Hibernate throwing a ConcurrentModificationException

I am writing some tests for a persistance layer I've been working on and I've ran into an exception that that I'm having trouble dealing with, a ConcurrentModificationException it's happening at org.hibernate.mapping.Table.cleanseUniqueKeyMap(Table.java:291) .
Which turns out to be this line of code:

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

After doing a little research I've found out that the exception is caused by one thread modifying this collection while this thread is iterating over it. That being said I feel like there's nothing that I'm doing that's causing this to happen any suggestions on troubleshooting?

BTW, Im using hibernate 4.1.5 . Idk if that clears anything up or not. Here's my test:

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

As you can see we try and initialize the dao Let's see that code:

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

Well that didn't show us much so let's look at the generic dao constructor and see if you see the problem there.

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

Now I'm not sure what kind of rabbit hole Persistance.createEntityManagerFactory is, but that is the last line of my code that gets executed before the exception occurs.

Concurrent modification happens when you iterate a collection in the for-each loop, and alter the collection somewhere else. One of the common solution is to use Iterator instead of for-each loop. Or have your Collection in synchronized block.

There are resources all over about it:

Avoiding ConcurrentModificationException , It says:

  1. You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.

  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.

  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. It is the recommended approach.

Also:

Concurrent Modification exception
How to debug ConcurrentModificationException?

Since it seems like a exception during internal housekeeping by Hibernate, I had assumed that its a bug. A quick search on Google does show a recently reported JIRA .

There is a resolution proposed but no idea when it will be released.

Hope this helps!

This happens because you have your loop going through a collection, then somewhere inside the loop, you change the collection you are iterating through, and you try to resume the loop as though nothing has changed.

I have had the same thing happen to me :

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

The problem is that you can't modify the list you are iterating through. The solution i opted for in my case was to make a new list, a copy of the original, to iterate through it, while modifying the original list :

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

Hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM