2

I am facing a problem with hibernate with multithreading.

I am developing a swing based application where there are some number of POJO classes. The relations among the classes: Category has a set of Protocols, Protocol has a set of Step, Step has a set of Mode. All the collections are loaded lazily with fetch = FetchType.LAZY. I am maintaining a single session for the application. After getting the list of all Category, I need to start some threads to do some operations on the category list. Here I am getting LazyInitializationException. The test code is as follows:

final List<Category> cats = protocolDao.getCategoryList();
for (int i = 0; i < 10; i++) {
new Thread("THREAD_" + i) {
    public void run() {
    try {
        for (Category category : cats) {
        Set&lt;Protocol> protocols = category.getProtocols();
            for (Protocol protocol : protocols) {
            Set&lt;Step> steps = protocol.getStep();
            for (Step step : steps) {
                step.getModes());
            }
            }
        }
        System.out.println(Thread.currentThread().getName()+"SUCCESS"  ;
        } catch (Exception e) {
        System.out.println("EXCEPTION ON " + Thread.currentThread().getName());
        }
    };
    }.start();
}

The dao method is as follows:

public List&lt;Category> getCategoryList() throws ProtocolException {
    try {
        Transaction transaction = session.beginTransaction();
    List list = session.createCriteria(Category.class)
        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
        .addOrder(Order.asc("categoryposition")).list();
    transaction.commit();
    return list;
    } catch (Exception e) {
       throw new ProtocolException(e);
    }
}

When I try to run the above code I get the following exception for some of the threads:


SEVERE: illegal access to loading collection
org.hibernate.LazyInitializationException: illegal access to loading collection
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:363)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
    at org.hibernate.collection.PersistentSet.toString(PersistentSet.java:332)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at com.mycomp.core.protocol.dao.test.TestLazyLoading$1.run(TestLazyLoading.java:76)

So some of the tasks are not completed. I cannot avoid multiple threads to work on the same category list(it works fine with single thread). Every thread requires to do its own task. The database is too big to avoid lazy loading. Can anyone help me how will I be able to work with multiple threads with the same category list?

1 Answer 1

2

You need to ensure that only the thread that gets your entities uses them. If you have a get ids and get by id method or similar:

final int[] catIds = protocolDao.getCategoryIds();
for (int i : catIds) {
  new Thread("THREAD_" + i) {
    public void run() {
      Category category = protocolDao.getCategory(i);
      Set<Protocol> protocols = category.getProtocols();
      for (Protocol protocol : protocols) {
        Set<Step> steps = protocol.getStep();
          for (Step step : steps) {
            step.getModes());
          }
      }
    };
  }.start();
}
Sign up to request clarification or add additional context in comments.

6 Comments

does it have anything to do with making any of the methods synchronized? had a similar problem myself and feel curious
@jere No, hibernate keeps it's session and transaction scope tied to a thread, which is why problems arise when using entities 'got' from another thread. synchronized ensures only one thread can execute that method at a time.
It is difficult to ensure the thread with corresponding entities, as one thread will display the data into the UI, whereas another thread prepare a document for printing, and there are other thread doing some back end processing, etc. All threads needs the entire collection. I have not made any of the method <code>synchronized</code> so far as only one thread is accessing the dao method. Also the object need to be processed in the thread are at different level, i.e. sometimes it is protocol, steps, etc.
@rich.okelly Do you mean that the getters of the collections should be made 'synchronized'?
@GBH No, any lazy loading MUST be done on the SAME thread that created the object, since this is how hibernate ties the entities to it's session and transaction states. If you need to lazily load child elements from a parent, this must be done on the same thread that gets the parent from the database. Marking methods synchronized will have no effect here.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.