3

I seem to be randomly getting the following LazyInitializationException in a Spring/MVC 3.0/Hibernate 3.5 application in spite of seeing the filter in the stack trace itself. Any idea on what I should look into?

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)

From the 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>

Update, adding definition of 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>
Abdullah Jibaly
  • 53,220
  • 42
  • 124
  • 197
  • Are you sure you always use `getCurrentSession()`? Also, show your configuration of `LocalSessionFactoryBean`. – axtavt Jun 07 '11 at 16:55
  • Yeah we always use `getCurrentSession()`, I've updated the bean definition above. – Abdullah Jibaly Jun 07 '11 at 17:06
  • 1
    Another possibility is you invalidated the session that entity was attached to by throwing an exception out of an @Transactional method. – Affe Jun 07 '11 at 17:08
  • @AbdullahJibaly How is the hibernateFilter mapped to the Dispatcher servlet here? I'm getting exactly the same problem although I have given all that is needed. – tintin Sep 09 '12 at 09:47

2 Answers2

6

Two most common causes I know of for lazy load exceptions with the filter on are either trying to access something after an exception has invalidated the Hibernate Session, or trying to access a field on something that was actually sitting around on the Web session and isn't attached.

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
  }
}

Obviously lots of code and annotations ommitted for clarity :)

@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";
  }
}
Affe
  • 47,174
  • 11
  • 83
  • 83
  • One thing I noticed in my stacktrace is that there is no controller. Could that somehow be related to the issue? – Abdullah Jibaly Jun 07 '11 at 17:57
  • We don't use sessions so I'm pretty sure it's not the latter, I'll need to look into the Transactional service calls. Thanks for the advice. – Abdullah Jibaly Jun 07 '11 at 17:59
  • 1
    Ya, from your stack trace it's clear it's happening in the JSP, but the root cause can still be the same, session isn't around anymore because it got closed by a rollback. Might be able to help more if you post some code. Can't really infer much from just config other than "looks ok" :) – Affe Jun 08 '11 at 01:52
  • I was able to verify that the cause was indeed the exception causing a rollback. Because this was in a retry loop I didn't realize this was the cause. I am doing an update on a model and manually forced a runtime exception. The second retry did go through correctly, but I got the exception above in the JSP. Does that make sense that the session is still around until it gets to the JSP? – Abdullah Jibaly Jun 08 '11 at 03:55
  • 2
    If the 'original' session gets invalidated, Spring will transparently create another when you do something new that needs one. The 'latest' HSession will be around when you get to the JSP, but this still leaves objects loaded in the first session in the detached state. – Affe Jun 08 '11 at 04:44
  • That's gotta be it, makes a lot of sense now. You rock! – Abdullah Jibaly Jun 08 '11 at 07:05
2

In spring MVC You should use OpenSessionInViewInterceptor instead of filter In my current project this is configured that way:

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

Where sessionFactory refers to org.springframework.orm.hibernate3.LocalSessionFactoryBean

Works flawless.

danny.lesnik
  • 18,479
  • 29
  • 135
  • 200
  • I'll give this a shot, but after some initial research I'm finding it hard to find any conclusive differences between the two. Know of any good reference on this? – Abdullah Jibaly Jun 07 '11 at 17:07
  • Actually, I added it from Spring manual, and only interceptor worked good for me. I think you need to make sure that your transactions are managed by Spring using @TRansactional or Aspects. – danny.lesnik Jun 07 '11 at 18:08
  • It looks like I have to use the filter version since I'm using SiteMesh (which needs access to the Hibernate session in my case). – Abdullah Jibaly Jun 07 '11 at 19:43
  • Yes it makes sense in your case. Then probably you need to check your transaction, may be you are closing transaction, while SiteMash is still using it. – danny.lesnik Jun 07 '11 at 20:35
  • @Abdullah where you able to sort your issue? it seems are currently in your position ,using sitemesh and freemarker.using transactional at service layer but still having Lazyinitialization problem. – black sensei Feb 23 '12 at 16:31
  • @blacksensei in our case it turned out to be that an exception was being thrown inside of a transactional section (which closes the session and recreates a new one). What we ended up doing is always re-reading the object from the database in every "retry". – Abdullah Jibaly Feb 23 '12 at 19:04
  • @Abdullah thanks for the reply, another question. is your interceptor in application Context or filter in web.xml – black sensei Feb 23 '12 at 20:37
  • @blacksensei we didn't use the interceptor approach, the way we had it defined as a filter (defined in web.xml) as shown in my question worked fine. – Abdullah Jibaly Feb 24 '12 at 19:32
  • Thank you, It works for me. Before I had to use @Proxy(lazy = false) in entity classes. You don't need to use LocalSessionFactoryBean. works perfectly – Pramod Jul 22 '12 at 12:52