2011-03-19 136 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也可以工作。