使用OpenSessionInViewInterceptor来避免LazyInitializationException

时间:2010-08-26 15:01:13

标签: hibernate spring jpa ejb lazy-loading

首先,我需要承认我是EJB,JPA和Spring的新手,因此我认为真实的许多事情可能都是错误的。

我正在构建一个EJB应用程序,其中有一个无状态会话bean用于检索许多JPA(Hibernate)实体。我认为这个普遍问题的问题是,当无状态返回任何实例时,我无法遍历这些实体的关系。我得到了可怕的LazyInitializationException。在许多情况下,我发现使用急切提取我可以避免异常,但这感觉更像是一种解决方法,而不是一个真正的修复。经过大量的谷歌搜索后,我发现(因为我使用的是弹簧)可能是实现这一目标的最具侵入性的方法是使用OpenSessionInViewInterceptor。

阅读this看起来很容易使用,但我无法映射文章中提到的文件。一种可能的解释是我使用的是Spring 3,因此文件的名称可能已经改变。我有一个 spring3app-servlet.xml ,其中声明了bean。我还有一个 web.xml ,其中设置了过滤器(我认为这个文件与spring 2.0一起使用,但它仍适用于3.0)。

进一步搜索让我意识到文件名不是我唯一关注的问题,因为我没有任何SessionFactory bean,我相信这是必要的。这导致我搜索有关SessionFactory bean的信息。

那次搜索让我意识到我可能需要.hbm.xml文件。我不确定这些文件是否真的需要,或者它们是否是传统hibernate-spring版本的必备条件。

tl; dr:我想要一个OpenSessionInViewInterceptor。我需要SessionFactory Bean吗?我需要.hbm.xml文件吗?我在哪里可以找到所有信息来设置它?

修改

也许解决方案是使用OpenSessionInViewFilter。我正在尝试使用它,但它仍然失败,但同样的例外。我正在阅读this以寻找解决方案。

1 个答案:

答案 0 :(得分:4)

首先,如果你想要一个全面的JPA解决方案,你应该使用OpenEntityManagerInViewFilter。这与OpenSessionInViewInterceptor类似,但对于JPA

对于会话bean,您将始终获得LazyInitializationException,因为该对象是在另一个会话中加载的。只能在当前的http请求中访问惰性字段。如果您在另一个http请求中访问该字段,您将收到LazyInitializationException。

(顺便说一下,hibernate将http请求定义为“Session”。但是Spring会话覆盖了多个http请求。是的,这很令人困惑)。

您可以采取哪些措施来避免LazyInitializationException:

  1. 重新加载会话bean。例如:

    MyObject objectFromDb = objectDAO.find(objectFromSession.getId());

  2. 或者在会话bean中设置字段时初始化字段:

    状态,Hibernate.initialize(场);

  3. (不要忘记递归所有儿童字段)


    好的,因为这是同一个会话,你需要一个OpenEntityManagerInViewFilter / OpenSessionInViewInterceptor,它将为每个Http请求创建一个Hibernate会话。所以在你的web.xml中输入一个条目:

        <filter>
            <filter-name>JpaFilter</filter-name>
            <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>JpaFilter</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
    

    OpenEntityManagerInViewFilter类似。还要确保在您的过滤器中注入“entityManagerFactory”bean。