如何在@PostContruct方法中手动管理Hibernate会话?

时间:2012-12-16 15:14:13

标签: spring hibernate lazy-loading

我的问题很简单。我想在Tomcat上加载应用程序时从数据库访问一些数据。为了在那个时间做某事我使用@PostConstruct(它正常工作)。

然而,在该方法中,我与DB建立了两个独立的连接:一个用于引入实体列表,另一个用于将它们添加到公共库中。第二步意味着一些用于解决一些延迟加载关联的幕后查询。以下是代码段:

@Override
@PostConstruct
public void populateLibrary() {
// query for the Book Descriptors - 1st query works!!!
List<BookDescriptor> bookDescriptors= bookDescriptorService.list();

Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
    transaction = session.beginTransaction();

        // resolving some lazy-loading associations - 2nd query fails!!!
    for (BookDescriptor book: bookDescriptors) {
         library.addEntry(book);
    }

    transaction.commit();
} catch (HibernateException e) {

    transaction.rollback();
    e.printStackTrace();
} finally {
    session.close();
}
}
正如我在评论中写的那样,第一个查询在第二个查询失败时有效。失败给出了:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java)
at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73)

因为我明确地打开并关闭了一个事务,所以这很奇怪。但是,如果我检查第一个查询的如何的一些细节,那么会话似乎是在幕后会话被绑定到AbstractLazyInitializer类。

我通过将for循环中的功能抽象为一个单独的服务类来解决我的问题,该服务类使用@Transactional(readOnly = true)进行注释。我仍然很困惑为什么我在这里发布的approch失败了。

如果有人提示,我会很高兴听到他们的声音。

1 个答案:

答案 0 :(得分:1)

您在第一个会话中加载实体,然后关闭此会话,然后打开一个新会话,并尝试延迟加载实体的集合。那不行。

要使延迟加载工作,必须将实体附加到打开的会话。只是打开另一个会话不会使您在连接到此新会话之前加载任何实体。与此同时,其他一些交易可能从根本上改变了数据库,实体再也不存在了......

最好的解决方案就是你所做的。将evrything封装到单个事务服务中。您也可以在调用第一个服务之前打开事务,但为什么要以编程方式处理事务,因为Spring会以声明方式为您执行此操作?