Announcement Announcement Module
Collapse
No announcement yet.
LazyInitializationException Hibernate Spring Help!!! Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • LazyInitializationException Hibernate Spring Help!!!

    Hi people, I am still struggling with the LazyInitializationException using Spring, Hibernate and JPA.

    This thread is in reference to the original thread:
    http://forum.springsource.org/showthread.php?t=76488

    Basically, I have cracked open the code and have some questions.

    In JpaTransactionManager, there is a function called doBegin. In the doBegin method, the workflow is always going into the first condition where this method is always fired: createEntityManagerForTransaction().
    Code:
    if (txObject.getEntityManagerHolder() == null ||
    					txObject.getEntityManagerHolder().isSynchronizedWithTransaction()) {
    				EntityManager newEm = createEntityManagerForTransaction();
    				if (logger.isDebugEnabled()) {
    					logger.debug("Opened new EntityManager [" + newEm + "] for JPA transaction");
    				}
    				txObject.setEntityManagerHolder(new EntityManagerHolder(newEm), true);
    			}

    Inside function createEntityManagerForTransaction(), I noticed that the original EntityManagerFactory (org.springframework.orm.jpa.LocalContainerEntityM anagerFactoryBean@1dc0d) defined in my data-access-context is overwritten for this: org.hibernate.ejb.EntityManagerFactoryImpl@1b3251d !

    Code:
    	EntityManagerFactory emf = getEntityManagerFactory();
    		if (emf instanceof EntityManagerFactoryInfo) {
    			emf = ((EntityManagerFactoryInfo) emf).getNativeEntityManagerFactory();
    		}
    In other words, the code asks for the original EntityManagerFactyory: getEntityManagerFactory which is cool. However, it then checks if it is an instance of EntityManagerFactoryInfo which is true. And because it is true, it is then overwritten by getNativeEntityManagerFactory!!
    The Session is bound to this new EntityManagerFactory and EntityManager.
    Maybe this is why I cannot access this same session again (and get the LazyLoadingException)?
    Basically from what I see, there is a conflict of EntityManagerFactories. There is the original one that is created but it is overwritten by getNativeEntityManagerFactory().
    The funny thing is this code seems to be always fired, so whats the point of OpenSessionInViewFilter/OpenEntityManagerInViewFilter???

    I have no applicationContext.xml in my WAR project (i.e transactionManager is defined once, no duplication). Instead I have my transactionManager hooked up in my data-access-context in web.xml like so:
    Code:
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value> 
    
    					 classpath:data-access-context.xml 
    		
    		</param-value>
    	</context-param>
    I know this accesses my transactionManager because if I remove this definition from web.xml, the application complains there is no entityManagerFactory.
    My data-access-context looks like this:
    Code:
    		<bean id="entityManagerFactory"
    			
    			class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean ">
    			
    			<property name="persistenceUnitName" value="dataAccessPU" />
    		</bean>
    		<!--  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> -->
    		<bean id="transactionManager"
    			class="org.springframework.orm.jpa.JpaTransactionManager">
    			<property name="entityManagerFactory"
    				ref="entityManagerFactory" />
    		</bean>
    I shouldn't have to go to such lengths to get OpenEntityManagerInViewFilter working.
    I believe at the root of it, it is a configuration issue and I am missing something...but I do not know what! I have spent hours and hours on this issue taking in all the tips, tricks and advice and have made some adjustments....but am still stuck.
    I also see other users on here who are battling the same issue.
    Can someone gimme a hand?
    Greatly appreciated.

    Here is the LazyInitializationException:
    Code:
    2009-09-06 13:39:47,531 DEBUG [http-80-1](org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:730)) - Initiating transaction commit
    2009-09-06 13:39:47,531 DEBUG [http-80-1](org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:451)) - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1dd2519]
    2009-09-06 13:39:47,546 DEBUG [http-80-1](org.springframework.orm.jpa.JpaTransactionManager.doCleanupAfterCompletion(JpaTransactionManager.java:534)) - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@1dd2519] after transaction
    2009-09-06 13:39:47,546 DEBUG [http-80-1](org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:313)) - Closing JPA EntityManager
    2009-09-06 13:39:47,546 DEBUG [http-80-1](com.logixplayer.pf.category.controller.CategoryController.onSubmit(CategoryController.java:42)) - category: Autos
    2009-09-06 13:39:47,546 ERROR [http-80-1](org.hibernate.LazyInitializationException.<init>(LazyInitializationException.java:19)) - failed to lazily initialize a collection of role: com.logixplayer.pf.domain.Category.categories, no session or session was closed
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.logixplayer.pf.domain.Category.categories, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at 80-1](org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:588)) - Could not complete request
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.logixplayer.pf.domain.Category.categories, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at com.logixplayer.pf.category.controller.CategoryController.onSubmit(CategoryController.java:45)
    	at org.springframework.web.servlet.mvc.SimpleFormController.onSubmit(SimpleFormController.java:409)
    	at org.springframework.web.servlet.mvc.SimpleFormController.onSubmit(SimpleFormController.java:381)
    	at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:267)
    	at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:265)
    	at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at 2009-09-06 13:39:47,546 DEBUG [http-80-1](org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:588)) - Could not complete request
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.logixplayer.publicfountain.domain.Category.categories, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    	at java.lang.Thread.run(Thread.java:595)
    2009-09-06 13:39:47,546 DEBUG [http-80-1](org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:119)) - Closing JPA EntityManager in OpenEntityManagerInViewFilter
    2009-09-06 13:39:47,546 DEBUG [http-80-1](org.springframework.orm.jpa.EntityManagerFactoryUtils.closeEntityManager(EntityManagerFactoryUtils.java:313)) - Closing JPA EntityManager

  • #2
    You cannot reuse objects which are stored in the http session. You will have to reload objects. Lazy loading only works for 1 request, after rendering the entitymanager is closed.

    Comment


    • #3
      Spring JPA Hibernate LazyloadingException

      Originally posted by Marten Deinum View Post
      You cannot reuse objects which are stored in the http session. You will have to reload objects. Lazy loading only works for 1 request, after rendering the entitymanager is closed.
      Hi Marten, thanks for the reply.
      Like I said, I was quoting my original thread at:http://forum.springsource.org/showthread.php?t=76488. All the background info is there.

      What is happening is all in one request as per my understanding.
      1. I get a list of categories from CategoryService in my CategoryController
      2. I iterate over each category
      3. I get sub-categories for each category --> BAM --> this is where I get a lazyloadingException

      Observe:
      Code:
      CategoryController
      	public ModelAndView onSubmit(Object command) throws ServletException {
      		
      		CategoryBean categoryBean = (CategoryBean) command;
      		
      		
      		//	call category service
      		ICategoryService categoryService = (ICategoryService)DataAccessServiceFactory.getBean("iCategoryService");
      		ITopicService topicService = (ITopicService)DataAccessServiceFactory.getBean("iTopicService");
      		List<Category> categories = categoryService.findByName("Autos", null);
      
      		for (Category category : categories) {
      			log.debug("category: "+category.getName());
      			
      			Set<Category> subCategories = category.getCategories(); LAZYLOADINGEXCEPTION HERE
      			for (Category subCategory : subCategories) {
      				log.debug("subCategory: "+subCategory.getName());
      				//Set<Topic> topics = subCategory.getTopics();
      				List<Topic> topics = topicService.findByCategoryID(subCategory.getCategoryId(), null);
      				log.debug("****now to get topics if there are any!****");
      				for (Topic topic : topics) {
      					log.debug("topic: "+topic.getTitle());
      					log.debug("****now to get submissions if there are any!****");
      					Set<Submission> submissions = topic.getSubmissions();
      					for (Submission submission : submissions) {
      						log.debug("submission topic: " +submission.getTopic());
      						log.debug("submission title: " +submission.getTitle());
      					}
      				}
      			}
      My service layer is transactional.
      But the minute the service layer returns the categories, the session is closed.
      Isn't the point of OpenSessionInViewFilter and OpenEntityManagerInViewFilter to keep the session open and alive so I can make calls like this:
      category.getCategories(); (which is declared lazy)
      after the session is closed??

      Well that's what the definition of OpenEntityManagerInViewFilter says:
      Code:
      Intended for the "Open EntityManager in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.
      Any ideas??
      p.s. please refer to http://forum.springsource.org/showthread.php?t=76488 for more background on this problem
      Thank you for your help

      Comment


      • #4
        Code:
        ICategoryService categoryService = (ICategoryService)DataAccessServiceFactory.getBean("iCategoryService");
        ITopicService topicService = (ITopicService)DataAccessServiceFactory.getBean("iTopicService");
        Code like this make me shudder.... You should inject those classes. What is your DataAccesServiceFactory doing?!

        Next to that from your thread I cannot make heads or tails... You use plain hibernate, then JPA. You only load 1 xml file (data-access.xml) what does it define? What does your (shudder) DataAccessServiceFactory do? Is your tx:annotation-driven in the same ApplicationContext as your services? Do you use component-scanning and are your services annotated with @Service (if so you risk duplicate service instances with all the trouble you get with that).

        So please post a whole overview of your configuration (filter, configuration files, servlet). If possible strip something down and make a zip file I can take a look at.
        Last edited by Marten Deinum; Sep 7th, 2009, 04:08 AM.

        Comment


        • #5
          Spring JPA Hibernate LazyloadingException

          Originally posted by Marten Deinum View Post
          Code:
          ICategoryService categoryService = (ICategoryService)DataAccessServiceFactory.getBean("iCategoryService");
          ITopicService topicService = (ITopicService)DataAccessServiceFactory.getBean("iTopicService");
          Code like this make me shudder.... You should inject those classes. What is your DataAccesServiceFactory doing?!
          Hi Marten, you got me thinking.
          Here is my DataAccessServiceFactory:
          Code:
          public class DataAccessServiceFactory {
          
          	private static ApplicationContext applicationContext;
          	private static final Log log = LogFactory.getLog(DataAccessServiceFactory.class);
          
          	public synchronized static ApplicationContext getApplicationContext() {
          		if (applicationContext == null) {
          			applicationContext = new ClassPathXmlApplicationContext("data-access-context.xml");
          		}
          		return applicationContext;
          	}
          
          	@SuppressWarnings("unchecked")
          	public static <T> T getBean(String beanName) {
          		return (T) getApplicationContext().getBean(beanName);
          	}
          In my DataAccessServiceFactory, I am accessing my data-access-context.xml which is where my DAO's and Services are defined.
          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans
          	xmlns="http://www.springframework.org/schema/beans"
          	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          	xmlns:p="http://www.springframework.org/schema/p"
          	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" xmlns:tx="http://www.springframework.org/schema/tx">
          
          
          		<bean id="entityManagerFactory"
          			
          			class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean ">
          			
          			<property name="persistenceUnitName" value="dataAccessPU" />
          		</bean>
          		<!--  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> -->
          		<bean id="transactionManager"
          			class="org.springframework.orm.jpa.JpaTransactionManager">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		
          		<!-- <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> -->
          		 <tx:annotation-driven transaction-manager="transactionManager"/> 
          	
          		<bean id="UserDAO"
          			class="com.logixplayer.pf.dao.UserDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="AttributesDAO"
          			class="com.logixplayer.pf.dao.AttributesDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="ProfileDAO"
          			class="com.logixplayer.pf.dao.ProfileDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="CommentDAO"
          			class="com.logixplayer.pf.dao.CommentDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="CategoryDAO"
          			class="com.logixplayer.pf.dao.CategoryDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="TopicDAO"
          			class="com.logixplayer.pf.dao.TopicDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<bean id="SubmissionDAO"
          			class="com.logixplayer.pf.dao.SubmissionDAO">
          			<property name="entityManagerFactory"
          				ref="entityManagerFactory" />
          		</bean>
          		<import resource="application-context-iAttributesService.xml"/>
          		<import resource="application-context-iCategoryService.xml"/>
          		<import resource="application-context-iTopicService.xml"/>
          		
          	</beans>
          Maybe what is happening is
          data-access-context.xml is being declared twice
          and that is confusing the OpenEntityManagerInViewFilter? It's just a thought...
          but I have made reference to data-access-context.xml once in web.xml:

          Code:
          	<filter-mapping>
          	    <filter-name>OpenEntityManagerInViewFilter</filter-name>
          	     <url-pattern>/*</url-pattern>
          	    <!-- <servlet-name>dispatcher</servlet-name> -->
          	</filter-mapping>
                	
              <listener>
          		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
          	</listener>
          	
          	<context-param>
          		<param-name>contextConfigLocation</param-name>
          		<param-value> 
          
          					 classpath:data-access-context.xml 
          		
          		</param-value>
          	</context-param>
          and then again, in my DataAccessServiceFactory...

          hmmm is there a way to just declare all the beans in data-access-context.xml just once? probably through the contextConfigLocation in web.xml and then reference this context somehow in my DataAccessServiceFactory?

          Your thoughts, thanks!

          Comment


          • #6
            And there is your problem... You are using 2 entitymanagers (that is why that code always makes me shudder). Basically rendering the one loaded by the ContextLoaderListener useless (and that is also the one used by the OpenEntityManagerInViewFilter) ).

            Again simply inject those classes, remove your Factory and it should work.

            If for some reason you really want to use that factory let it implement ApplicationContextAware and declare it in your data-access.xml file.

            Code:
            public class DataAccessServiceFactory implements ApplicationContextAware {
            
            	private static ApplicationContext applicationContext;
            	private static final Log log = LogFactory.getLog(DataAccessServiceFactory.class);
                 
                   public void setApplicationContext(ApplicationContext context) {
                     applicationContext=context;
                   }
            
            	@SuppressWarnings("unchecked")
            	public static <T> T getBean(String beanName) {
            		return (T) applicationContext.getBean(beanName);
            	}
            Code:
            <bean class="DataAccessServiceFactory" />
            However I really suggest removing that class and simply inject your dependencies it is way easier, less error prone.

            Comment


            • #7
              Context loading question

              Originally posted by Marten Deinum View Post
              And there is your problem... You are using 2 entitymanagers (that is why that code always makes me shudder). Basically rendering the one loaded by the ContextLoaderListener useless (and that is also the one used by the OpenEntityManagerInViewFilter) ).

              Again simply inject those classes, remove your Factory and it should work.

              If for some reason you really want to use that factory let it implement ApplicationContextAware and declare it in your data-access.xml file.

              Code:
              public class DataAccessServiceFactory implements ApplicationContextAware {
              
              	private static ApplicationContext applicationContext;
              	private static final Log log = LogFactory.getLog(DataAccessServiceFactory.class);
                   
                     public void setApplicationContext(ApplicationContext context) {
                       applicationContext=context;
                     }
              
              	@SuppressWarnings("unchecked")
              	public static <T> T getBean(String beanName) {
              		return (T) applicationContext.getBean(beanName);
              	}
              Code:
              <bean class="DataAccessServiceFactory" />
              However I really suggest removing that class and simply inject your dependencies it is way easier, less error prone.
              Hey Marten, thanks so much for the tip, you are the man!
              But I am just trying to get what you are saying, so if I go with the first option, how do I actually call DataAccessServiceFactory?
              DataAccessServiceFactory DataAccessServiceFactory = (DataAccessServiceFactory)DataAccessServiceFactory .getBean("DataAccessServiceFactory");?
              That isn't working. Basically I need a way to load data-access-context.xml , but yeah actually it was already loading though
              Code:
              	<param-name>contextConfigLocation</param-name>
              		<param-value> 
              
              					 classpath:data-access-context.xml 
              		
              		</param-value>
              Not sure how to reference DataAccessServiceFactory, apparently yeah its already loaded through web.xml (if declared as a bean in data-access-context.xml)

              if I go with option 2, are you suggesting injecting the CategoryService right into my controller? I don't really know how to do this.
              This part shouldnt be that hard :P

              Comment


              • #8
                Option 2, it is no different then injecting your entityManagerFactory into your dao.
                Code:
                public class CategoryController extends SimpleFormController{
                
                  private ICategoryService categoryService;
                
                  public void setCategoryService(ICategoryService categoryService) {
                    this.categoryService=categoryService;  
                  }
                
                
                  public ModelAndView onSubmit(Object command) throws ServletException {
                		
                	CategoryBean categoryBean = (CategoryBean) command;
                		
                	//	call category service
                	List<Category> categories = categoryService.findByName("Autos", null);
                
                
                }
                xml

                Code:
                <bean id="categoryController" class="CategoryController">
                  <property name="categoryService" ref="categoryService" />
                </bean>
                Of course the same goes for your services etc.

                If you really really want to use the service. You don't need to retrieve it from the application context you can use it just as you are used to. However you want to use 1 single instance of the ApplicationContext (hence the ApplicationContextAware and registering it in the context to get a reference to the context).

                Comment


                • #9
                  Context loading

                  Originally posted by Marten Deinum View Post
                  Option 2, it is no different then injecting your entityManagerFactory into your dao.
                  Code:
                  public class CategoryController extends SimpleFormController{
                  
                    private ICategoryService categoryService;
                  
                    public void setCategoryService(ICategoryService categoryService) {
                      this.categoryService=categoryService;  
                    }
                  
                  
                    public ModelAndView onSubmit(Object command) throws ServletException {
                  		
                  	CategoryBean categoryBean = (CategoryBean) command;
                  		
                  	//	call category service
                  	List<Category> categories = categoryService.findByName("Autos", null);
                  
                  
                  }
                  xml

                  Code:
                  <bean id="categoryController" class="CategoryController">
                    <property name="categoryService" ref="categoryService" />
                  </bean>
                  Of course the same goes for your services etc.

                  If you really really want to use the service. You don't need to retrieve it from the application context you can use it just as you are used to. However you want to use 1 single instance of the ApplicationContext (hence the ApplicationContextAware and registering it in the context to get a reference to the context).
                  hmmm okay, need to think about this more, its almost 6:30 in the morning!
                  BUt listen, I really appreciate the time you took out.
                  Very good.

                  p.s. if I need some more help, I will reach out :P

                  Thanks a million!!

                  Comment


                  • #10
                    I wanted to second the solution to this problem. I just started on a project that I "inherited". They had exactly the same problem with that LazyinitializationException, and they "solved" it by setting lazy="false" in all Hibernate mapping files

                    The cause was the same: they uploaded the bean configuration file twice, leading to the "more-than-one" SessionFactory and that confused the OpenSessionInViewFilter.

                    They had however a specific reason for loading it more than once: they loaded the beans in the web part of the project and they loaded them a second time in the business layer (completely separate from the web part of the project).

                    I solved this dependency by using the following blogs:
                    - Using a shared parent application context in a multi-war Spring application.
                    - Access the Spring-ApplicationContext from everywhere in your Application.

                    This helped me to remove all "loads" of bean classes, except in the web part, where it belonged. Now I could let the program fetch the stuff lazily, which improved its performance a lot

                    Hope this experience is useful for other people.

                    Comment

                    Working...
                    X