我有关于Hibernate和延迟加载的问题。
背景: 我有一个Spring MVC Web应用程序,我使用Hibernate作为我的持久层。我正在使用OpenSessionInViewFilter使我能够在视图层中延迟加载实体。我正在扩展HibernateDaoSupport类并使用HibernateTemplate来保存/加载对象。一切都运作良好。到目前为止。
问题: 我有一个可以通过Web请求启动的任务。当请求被路由到控制器时,控制器将为此任务创建新的Runnable并启动线程以运行任务。因此原始线程将返回并且放入ThreadLocal(通过OpenSessionInViewFilter)的Hibernate会话不可用于Task的新线程。因此,当任务执行某些数据库操作时,我会得到臭名昭着的LazyInitializationException。
任何人都可以建议我可以为任务提供Hibernate会话的最佳方法吗?
感谢阅读。
答案 0 :(得分:5)
将Runnable
设为一个Spring bean并在@Transactional
上添加run
注释。必须警告您,此异步任务不会在与Web请求相同的事务中运行。
请不要启动新主题,请使用pooling / executor。
答案 1 :(得分:1)
以下是有关如何在Runnable
:
@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都可以正常工作。
答案 2 :(得分:0)
我是否理解正确,您想在完全专用的后台线程中执行某些操作,对吧?在这种情况下,我建议你根本不访问Hibernates OpenSessionInViewFilter以及该线程的进一步会话逻辑,因为它会被正确记录,在解耦线程中运行,因此在原始线程中加载信息(即,处理了最初的HttpRequest)。我认为在该线程中自己打开和关闭会话是明智的。
否则,您可能会质疑为什么要在分离的线程中运行该操作。可能是正常运行操作并在此期间为用户提供一些“加载”屏幕就足够了吗?