如何在预定的工作中解决LazyInitializationException?

时间:2010-06-07 19:59:20

标签: hibernate spring lazy-loading

我正在研究部署在Tomcat上的J2EE服务器应用程序。我使用Spring源作为MVC框架,使用Hibernate作为ORM提供程序。我的对象模型有很多Lazy关系(根据请求获取依赖对象)。高级设计就像服务级方法调用几个DAO方法来执行数据库操作。可以从Flex UI或作为计划作业调用服务方法。当从Flex UI调用它时,服务方法工作正常,即它使用DAO方法获取一些对象,甚至Lazy加载工作。这可以通过使用配置了UI servlet的OpenSessionInViewFilter实现。

但是当相同的服务方法被调用为计划Job时,它会给出LazyInitializationException。我无法配置OpenSessionInViewFilter,因为没有与之关联的servlet或UI请求。

我尝试围绕预定作业方法配置Transaction,以便服务方法启动事务,并且所有DAO方法都参与同一事务,希望事务保持活动状态,并且hibernate会话将可用。但它不起作用。

请建议是否有人能够使这样的配置正常工作。如果需要,我可以发布Hibernate配置和日志消息。

非常感谢您的帮助!

Shreerang

3 个答案:

答案 0 :(得分:3)

最后,我在阅读了Spring Transaction参考资料后能够解决我的问题。 之前我曾尝试编写一个切入点的表达式来在Transaction中运行我的预定jon。但是切入点是使用OR(||)并且在开始执行时它不知道它没有拿起我的方法。因此,交易从未公开过。 (我已经为我的DAO方法提供了一个工作点切割表达式,我试图在该切入点中添加我的预定方法。)

然后我找到了一种以编程方式打开事务的方法来解决我的问题。为了他人的利益,这里有代码片段:

       transactionTemplate.execute(new TransactionCallbackWithoutResult() {
          protected void doInTransactionWithoutResult(TransactionStatus status) {
                // Invoke the real method inside transaction context
                doWork();
          }
        });

有关TransactionTemplate的详细信息,请参阅Spring Source文档: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-programmatic

答案 1 :(得分:2)

OpenSessionInViewFilter内的代码并不复杂,我已成功修改源代码以满足我自己的需求,它真正需要的是延迟加载的线程。

我也使用Quartz进行大量的预定作业,它与容器管理的事务非常合作。我在代码退出事务边界之前使用了几次确保延迟集合的技巧是创建一个专用方法,我调用必要的方法:

@Transactional
private SomeOobj getSomeObj(Long id) {
  SomeObj o = someObjDao.find(id);
  o.getLazyCollection().size(); // <- load the collection
  return o;
}

在这些情况下,最好在第一次获取对象时急切地加载所需的数据,但我知道它并不总是一个选项。祝你好运。

答案 2 :(得分:1)

OpenSessionInViewFilter无论如何都是一个黑客攻击,过分依赖它并不好。

更好的通用解决方案是编写hibernate查询,以便急切地获取数据,而不是懒惰。这意味着使用fetch joins

如果这不可行或不实用,那么您的计划任务可以在transaction内执行整个工作。这应该保持会话开放直到它完成。