0

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

但是,在该方法中,我与数据库建立了 2 个单独的连接:一个用于带来实体列表,另一个用于将它们添加到公共库中。第二步意味着一些用于解决一些延迟加载关联的幕后查询。这是代码片段:

@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) 进行注释。我仍然对为什么我在这里发布的方法失败感到困惑。

如果有人有一些提示,我会很高兴听到他们。

4

1 回答 1

1

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

为了使延迟加载起作用,实体必须附加到打开的会话。仅打开另一个会话不会使您在附加到此新会话之前加载的任何实体。与此同时,其他一些事务可能从根本上改变了数据库,实体不再存在......

最好的解决方案是你所做的。将所有内容封装到单个事务服务中。您也可以在调用第一个服务之前打开事务,但是为什么要以编程方式处理事务,因为 Spring 以声明方式为您完成呢?

于 2012-12-16T15:25:32.467 回答