【问题标题】:LazyInitializationException in spite of OpenSessionInViewFilter尽管有 OpenSessionInViewFilter,但 LazyInitializationException
【发布时间】:2011-06-07 16:40:45
【问题描述】:

尽管在堆栈跟踪本身中看到过滤器,但我似乎在 Spring/MVC 3.0/Hibernate 3.5 应用程序中随机获得以下 LazyInitializationException。知道我应该研究什么吗?

07 Jun 2011 13:48:47,152 [ERROR]  (http-3443-2) org.hibernate.LazyInitializationException: could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.test.Image_$$_javassist_18.getMyKey(Image_$$_javassist_18.java)
    at com.test.AppTagHelper.getAssetUrl(AppTagHelper.java:66)
    at sun.reflect.GeneratedMethodAccessor81.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.el.parser.AstFunction.getValue(AstFunction.java:110)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
    at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:935)
    at org.apache.jsp.WEB_002dINF.view.home_jsp._jspx_meth_c_005fout_005f2(home_jsp.java:1027)
    at org.apache.jsp.WEB_002dINF.view.home_jsp._jspx_meth_c_005fwhen_005f1(home_jsp.java:1002)
    at org.apache.jsp.WEB_002dINF.view.home_jsp._jspx_meth_c_005fchoose_005f1(home_jsp.java:969)
    at org.apache.jsp.WEB_002dINF.view.home_jsp._jspx_meth_display_005fcolumn_005f0(home_jsp.java:867)
    at org.apache.jsp.WEB_002dINF.view.home_jsp._jspService(home_jsp.java:214)
    <<VARIOUS SPRING FILTERS>>
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)

来自web.xml

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>
        org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
    <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>*.json</url-pattern>
</filter-mapping>

更新,添加SessionFactoryBean的定义:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" depends-on="dataSource">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.test.model" />
    <property name="schemaUpdate" value="false" />
    <property name="eventListeners">
      <map>
        <!-- Create -->
        <entry key="pre-insert">
          <ref local="hibernateCreateListener"/>
        </entry>
        <entry key="post-insert">
          <ref local="hibernateRevisionListener"/>
        </entry> 
        <!-- Update -->
        <entry key="pre-update">
          <ref local="hibernateUpdateListener"/>
        </entry>
        <entry key="post-update">
          <ref local="hibernateRevisionListener"/>
        </entry>
        <entry key="post-delete">
          <ref local="hibernateRevisionListener"/>
        </entry>
        <entry key="pre-collection-update">
          <ref local="hibernateRevisionListener"/>
        </entry>
        <entry key="post-collection-recreate">
          <ref local="hibernateRevisionListener"/>
        </entry>
        <entry key="pre-collection-remove">
          <ref local="hibernateRevisionListener"/>
        </entry>                   
      </map>
    </property>
    <property name="entityInterceptor">
      <ref bean="hibernateAuditInterceptor"/>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
        <prop key="hibernate.default_schema">${app.databaseSchema}</prop>                 
        <prop key="hibernate.show_sql">false</prop>
        <prop key="hibernate.format_sql">false</prop>
        <prop key="hibernate.use_sql_comments">false</prop>
        <prop key="hibernate.connection.oracle.jdbc.ReadTimeout">60000</prop>
        <prop key="org.hibernate.envers.revisionTypeFieldName">REV_TYPE</prop>
        <prop key="org.hibernate.envers.revisionFieldName">REV_ID</prop>        
      </props>
    </property>
  </bean>

【问题讨论】:

  • 你确定你总是使用getCurrentSession()吗?另外,请显示您的LocalSessionFactoryBean 配置。
  • 是的,我们一直使用getCurrentSession(),我已经更新了上面的bean定义。
  • 另一种可能性是您通过从 @Transactional 方法中抛出异常来使实体附加到的会话无效。
  • @AbdullahJibaly hibernateFilter 是如何映射到这里的 Dispatcher servlet 的?尽管我已经提供了所有需要的东西,但我遇到了完全相同的问题。

标签: java hibernate spring open-session-in-view


【解决方案1】:

我所知道的延迟加载异常的两个最常见原因是,在异常使 Hibernate 会话无效后尝试访问某些内容,或者尝试访问某些内容上的字段实际上坐在 Web 会话上并且没有附加。

public interface EntityService {

  @Transactional
  EntityA getA(Long id);

  @Transactional
  EntityB getB(Long id);
}

public class WebPageController {

  public void handleGet(Long id1, Long id2) {
    EntityA a = entityService.getA(id1);
    try {
      EntityB b = entityService.getB(id2);
    } catch (Exception e) {
      //print somthething
    }
    a.accessLazyField(); //will throw lazy load after getB throws exception
  }
}

为了清楚起见,显然省略了很多代码和注释:)

@SessionAttributes("model")
public class WebPageController {

  @ModelAttribute("model")
  @RequestMapping(method=RequestMethod.GET)
  public EntityA handleGet(Long id) {
    return entityService.getA(id);
  }

  @RequestMapping(method=RequestMethod.POST)
  public String handlePost(@ModelAttribute("model") EntityA a) {
    a.accessLazyField(); //will throw lazy load if the field was not accessed during original page rendering
    return "viewName";
  }
}

【讨论】:

  • 我在堆栈跟踪中注意到的一件事是没有控制器。这可能与问题有关吗?
  • 我们不使用会话,所以我很确定不是后者,我需要查看事务服务调用。感谢您的建议。
  • 是的,从您的堆栈跟踪来看,很明显它发生在 JSP 中,但根本原因仍然是相同的,会话不再存在,因为它被回滚关闭了。如果您发布一些代码,可能会提供更多帮助。除了“看起来不错”之外,不能从配置中推断出太多:)
  • 我能够验证原因确实是导致回滚的异常。因为这是在重试循环中,所以我没有意识到这是原因。我正在对模型进行更新并手动强制运行时异常。第二次重试确实正确完成,但我在 JSP 中得到了上述异常。会话在到达 JSP 之前仍然存在是否有意义?
  • 如果“原始”会话失效,当你做一些新的事情需要一个时,Spring 会透明地创建另一个。当您到达 JSP 时,“最新”的 HSession 就会出现,但这仍然会使在第一个会话中加载的对象处于分离状态。
【解决方案2】:

在 spring MVC 中你应该使用 OpenSessionInViewInterceptor 而不是 filter 在我当前的项目中,这是这样配置的:

<mvc:annotation-driven/>
<mvc:interceptors>
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
</mvc:interceptors>

其中 sessionFactory 指的是org.springframework.orm.hibernate3.LocalSessionFactoryBean

完美无瑕。

【讨论】:

  • 我会试一试,但经过一些初步研究后,我发现很难找到两者之间的任何决定性差异。知道这方面有什么好的参考吗?
  • 实际上,我是从 Spring 手册中添加的,只有拦截器对我有用。我认为您需要确保 Spring 使用 @TRansactional 或 Aspects 管理您的事务。
  • 看来我必须使用过滤器版本,因为我使用的是 SiteMesh(在我的情况下需要访问 Hibernate 会话)。
  • 是的,在您的情况下这很有意义。那么可能您需要检查您的交易,可能是您正在关闭交易,而 SiteMash 仍在使用它。
  • @Abdullah 您可以在哪里解决您的问题?似乎目前处于您的位置,使用 sitemesh 和 freemarker。在服务层使用事务,但仍然存在延迟初始化问题。
猜你喜欢
  • 2016-08-27
  • 2012-09-03
  • 1970-01-01
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多