我正在阅读Hibernate的一些实体:
Criteria criteria = session.createCriteria(…);
List<Entity> list = (List<Entity>) criteria.list();
现在我正在迭代此列表,并希望将Runnable
内的每个对象发送到Executor
。因此,我使用RunnableBean
。
for (Entity entity : list) {
IRunnableBean runnableBean = (IRunnableBean)
applicationContext.getBean("myRunnableBean", IRunnableBean.class);
runnableBean.setEntity(entity);
executor.execute(runnableBean);
}
RunnableBean
看起来像这样:
RunnableBean implements IRunnableBean {
// Setter
@Transactional
void run() {
entity.getMyCollection();
}
}
当我访问该集合时,我收到org.hibernate.LazyInitializationException
(no session or session was closed
)。
在Spring的日志中,我看到正确添加了事务方法run()
。我做错了什么?
答案 0 :(得分:2)
我猜你正在使用Spring's OpenSessionInViewFilter。如果是这样,则会出现此行为。 Filter将数据库连接放在线程本地上下文中,这在RunnableBean
。
由于myCollection
未被急切加载,因此Spring无法访问RunnableBean
内的数据库连接,无法加载它。你需要:
RunnableBean
; RunnableBean
,而不是传递对象并加载RunnableBean
或者,您可以让您的实体热切地加载myCollection
,但这会使整个加载过程变慢。
答案 1 :(得分:0)
只需在已编写的for
循环中添加以下行:
Hibernate.initialize(entity.getMyCollection());
这会急切地加载集合而不是懒惰:不再LazyInitializationException
。
答案 2 :(得分:0)
我也猜测(比如@mindas)你的bean中的事务是不可用的,因为它运行在与持有事务的线程不同的线程中。根据我的经验,spring还使用线程本地来解析范围内的代理,因此这些代码在异步运行的bean中都不起作用。
基本上我会尽量避免以异步方式运行需要事务的逻辑,因为异步调用运行的时间较长(否则,为什么要使用异步调用?)这会阻止事务和/或导致超时。
来自jpa的标准api提供了仅针对特定查询急切地获取关系的方法。也许这可能是一个选择?否则,访问集合的size()方法将初始化它。