2011-03-19 135 views
4

我有一個關於Hibernate和延遲加載的問題。休眠會話線程

背景: 我有一個Spring MVC web應用程序,我使用Hibernate作爲我的持久層。我正在使用OpenSessionInViewFilter讓我在視圖層中延遲加載實體。我擴展了HibernateDaoSupport類並使用HibernateTemplate來保存/加載對象。一切都工作得很好。到現在爲止。

問題: 我有一個任務可以通過web請求啓動。當請求被路由到控制器時,控制器將爲該任務創建一個新的Runnable並啓動該線程來運行該任務。因此,原始線程將返回,並且放置在ThreadLocal(由OpenSessionInViewFilter)中的Hibernate會話不可用於任務的新線程。所以當任務做了一些數據庫的工作時,我得到了臭名昭着的LazyInitializationException。

任何人都可以提出我可以讓Hibernate會話可用於任務的最佳方式嗎?

感謝您的閱讀。

回答

4

將您的Runnable設爲春豆並在run上添加@Transactional註釋。必須警告您,此異步任務不會與您的Web請求在同一事務中運行。

請不要啓動新線程,請使用pooling/executor。

+1

什麼意思是不開始新的線程? – Dejell 2014-05-05 20:04:27

+0

@Dejel可能使用[ScheduledThreadPoolExecutor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html)或類似的機制。 – user11153 2014-09-18 12:23:12

0

我理解正確嗎,你想在完全專用的後臺線程中執行一些操作,對嗎?在這種情況下,我建議你不要訪問Hibernates OpenSessionInViewFilter和該線程的進一步會話邏輯,因爲它會,你會正確地注意到,運行在一個分離的線程中,因此信息加載在原始線程中(即,那個處理了最初的HttpRequest)。我認爲在該主題中自己打開和關閉會話是明智的。

否則,您可能會質疑爲什麼您要在單獨的線程中運行該操作。在正常情況下運行操作就足夠了,同時向用戶提供一些「加載」屏幕?

1

下面是關於如何使用Runnable內Hibernate的Session的工作示例:

@Service 
@Transactional 
public class ScheduleService { 

    @Autowired 
    private SessionFactory  sessionFactory; 

    @Autowired 
    private ThreadPoolTaskScheduler  scheduler; 

    public void doSomething() { 

     ScheduledFuture sf = scheduler.schedule(new Runnable() { 
      @Override 
      public void run() { 
       SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(scheduler); 
       final Session session = sessionFactory.openSession(); 
       // Now you can use the session 
      } 
     }, new CronTrigger("25 8 * * * *")); 
    } 
} 

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext()需要參考任何Spring管理的bean,因此調度本身是好的。任何其他Spring管理bean也可以工作。