我的问题很简单。我想在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失败了。
如果有人提示,我会很高兴听到他们的声音。
答案 0 :(得分:1)
您在第一个会话中加载实体,然后关闭此会话,然后打开一个新会话,并尝试延迟加载实体的集合。那不行。
要使延迟加载工作,必须将实体附加到打开的会话。只是打开另一个会话不会使您在连接到此新会话之前加载任何实体。与此同时,其他一些交易可能从根本上改变了数据库,实体再也不存在了......
最好的解决方案就是你所做的。将evrything封装到单个事务服务中。您也可以在调用第一个服务之前打开事务,但为什么要以编程方式处理事务,因为Spring会以声明方式为您执行此操作?