2012-12-16 17 views
0

我的問題很簡單。當應用程序加載到Tomcat上時,我想從數據庫訪問一些數據。爲了在那個時間點做些事情,我使用了@PostConstruct(它可以正常工作)。如何在@PostContruct方法中手動管理Hibernate會話?

但是,在該方法中,我將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)進行註釋。至於爲什麼我在這裏發佈的新聞稿失敗,我仍感到困惑。

如果有人有一些提示,我會很高興聽到他們。

回答

1

您可以在第一個會話中加載實體,然後關閉此會話,然後打開一個新會話並嘗試延遲加載實體的集合。這是行不通的。

對於延遲加載工作,實體必須連接到打開的會話。只需打開另一個會話,就不會在附加到此新會話之前創建您已加載的任何實體。與此同時,其他一些交易可能已經徹底改變了數據庫,實體不能再存在了......

最好的解決方案就是你所做的。將evrything封裝成單一交易服務。您也可以在調用第一個服務之前打開事務,但是爲什麼以編程方式處理事務,因爲Spring是以聲明方式處理的?

+0

非常好的解釋。非常感謝你! –