Reputation:
I'm reading some entities with Hibernate:
Criteria criteria = session.createCriteria(…);
List<Entity> list = (List<Entity>) criteria.list();
Now I'm iterating over this list and want to send every object inside a Runnable
to an Executor
. I therefore use a RunnableBean
.
for (Entity entity : list) {
IRunnableBean runnableBean = (IRunnableBean)
applicationContext.getBean("myRunnableBean", IRunnableBean.class);
runnableBean.setEntity(entity);
executor.execute(runnableBean);
}
The RunnableBean
looks like this:
RunnableBean implements IRunnableBean {
// Setter
@Transactional
void run() {
entity.getMyCollection();
}
}
When I'm accessing the collection, I'm getting a org.hibernate.LazyInitializationException
(no session or session was closed
).
In Spring's log I see that the transactional method run()
is correctly added. What am I doing wrong?
Upvotes: 0
Views: 1147
Reputation: 2112
I would also guess (like @mindas) that the transaction is not available in your bean because it runs in a different thread than the one that holds the transaction. As far as my experience goes spring also uses thread locals to resolve scoped proxies, so these won't work either in a bean that is run asynchronously.
Basically I would try to avoid running logic that requires a transaction in an asynchronous fashion, since asynchronous calls run for a longer time (otherwise, why use async calls?) and this will block the transaction and/or lead to timeouts.
The criteria api from jpa offers ways to fetch a relation eagerly only for a specific query. Maybe that could be a choice? Otherwise accessing the size() method of a collection will initialize it.
Upvotes: 0
Reputation: 48837
Just add the following line within your already written for
loop:
Hibernate.initialize(entity.getMyCollection());
This is load the collection eagerly instead of lazily: no LazyInitializationException
anymore.
Upvotes: 0
Reputation: 26713
I guess you are using Spring's OpenSessionInViewFilter. If so, this behaviour is expected. Filter puts the database connection in the thread local context which is not available in your RunnableBean
.
As myCollection
isn't loaded eagerly, Spring does not have access to the database connection inside RunnableBean
and can't load it. You need to:
RunnableBean
;RunnableBean
instead of passing object and load the collection inside RunnableBean
Alternatively, you can make your entity to load myCollection
eagerly but this will make the overall loading process slower.
Upvotes: 2