Hibernate/Spring3: could not initialize proxy - no Session

18,689

Solution 1

Your stack trace does not match up with the sample code you posted for UserDao. The trace says that you're calling HibernateTemplate.initialize() from UserDao.lookupUser(), but your sample code is doing no such thing (as well it shouldn't, initialize() should not be called here).

Edit: OK, with the new stack trace, it seems the problem is simply that you're calling hibernateTemplate.load(), which should only be used in specific circumstances (and this isn't one of them). You should probably be calling hibernateTemplate.get().

Solution 2

When you do the dao call, you "load" the object. Load does not hit the database, it will return a proxy onto the object so that the database is only hit when absolutely necessary.

You did not start a transaction before the load - the load works because you have non transactional reads turned on (it's on by default). It doesn't say, sorry, no transaction (it basically creates one for you to do the read, which ends immediately).

Thus when you do the getName when it actually has to hit the database it tells you "no session" because the session which did load that object is closed (it was closed immediately).

What you need to do to fix it is start the transaction at the beginning of the servlet call and end it at the end - that way when you do the getName the session will still be available.

There's probably something in spring which will handle this plumbing for you.

Share:
18,689
niklassaers
Author by

niklassaers

Updated on June 05, 2022

Comments

  • niklassaers
    niklassaers almost 2 years

    I'm new at Spring, so I put Spring 3.0M3 on a Tomcat server on my Mac, made an Eclipse project, completed a Hello World and then wanted to make an object persist with Hibernate. I've made a User table on my MySQL server, made a User object with all getters and setters (I really wish Java would take a queue from Objective-C here and add dynamic properties. Too much code clutter with generated property-code), made a UserDao object to look up and save a User, and made the bean config. It goes fairly well... except for that the session isn't initialized. Why is this? I can access the database just fine from this computer using those credentials.

    I realize that this is probably just normal beginner stuff, but all I've found on the error while googling has been people that are loosing the sessions mid-way when transitioning from Hibernate 2 to 3. I'm not transitioning, and as far as I can tell the session is never made.

    Here's my error:

    SEVERE: Servlet.service() for servlet HelloApp threw exception
    org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
        at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
        at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
        at com.saers.data.entities.User$$EnhancerByCGLIB$$c2f16afd.getName(<generated>)
        at com.saers.view.web.controller.HelloWorldController.handleRequestInternal(HelloWorldController.java:22)
        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:763)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:709)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:613)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:525)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        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.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
        at 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:637)
    

    Here is my servlet config for the related beans:

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName"   value="com.mysql.jdbc.Driver" />
        <property name="url"     value="jdbc:mysql://10.0.0.3:3306/HelloDB" />
        <property name="username" value="hello" />
        <property name="password" value="w0rld" />
        <property name="initialSize" value="2" />
        <property name="maxActive" value="5" />
      </bean>
    
      <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
          <list>
            <value>com.saers.data.entities.User</value>
          </list>
        </property>
        <property name="hibernateProperties">
          <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.lazy">false</prop>
          </props>
        </property>
      </bean>
    
      <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
      </bean>
    
      <bean id="userDAO" class="com.saers.data.dao.UserDao">
        <property name="sessionFactory" ref="sessionFactory"/>
      </bean>
    
      <bean id="txProxyTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
          <props>
            <prop key="add*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="delete*">PROPAGATION_REQUIRED</prop>
            <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
          </props>
        </property>
      </bean>
    
      <bean id="userService" parent="txProxyTemplate">
        <property name="target">
          <bean class="com.saers.business.UserServiceImpl">
            <property name="userDao" ref="userDAO"/>
          </bean>
        </property>
        <property name="proxyInterfaces" value="com.saers.business.UserService"/>
      </bean>
    
      <bean name="/" class="com.saers.view.web.controller.HelloWorldController">
        <property name="userService" ref="userService"/> 
      </bean>
    

    Here is my User class:

    package com.saers.data.entities;
    
    import java.util.Date;
    import java.io.Serializable;
    
    import javax.persistence.*;
    
    @Entity
    @Table(name = "User")
    public class User implements Serializable {
    
        private static final long serialVersionUID = -6123654414341191669L;
    
        @Id
        @Column(name = "WebUserId")
        private String WebUserId;
    
        @Column(name = "Name")
        private String Name;
        /**
         * @return the webUserId
         */
        public synchronized String getWebUserId() {
            return WebUserId;
        }
        /**
         * @param webUserId the webUserId to set
         */
        public synchronized void setWebUserId(String webUserId) {
            WebUserId = webUserId;
        }
        /**
         * @return the name
         */
        public synchronized String getName() {
            return Name;
        }
        /**
         * @param name the name to set
         */
        public synchronized void setName(String name) {
            Name = name;
        }
    }
    

    And here is my UserDao:

    package com.saers.data.dao;
    
    import java.util.List;
    
    import com.saers.data.entities.User;
    
    import org.springframework.orm.hibernate3.support.*;
    
    
    public class UserDao extends HibernateDaoSupport {
    
        public void saveUser(User user) {
            getHibernateTemplate().saveOrUpdate(user);
        }
    
        public User lookupUser(String WebUserId) {
            User user = getHibernateTemplate().load(User.class, WebUserId);
            return user;
            return user;
        }
    }
    

    Here's my UserService interface

    public interface UserService {
    
        public User lookupUser(String webUserId);
        public void setUserDao(UserDao userDao);
    }
    

    and its implementation:

    public class UserServiceImpl implements UserService {
    
        private UserDao userDao;
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public User lookupUser(String webUserId) {
    
            return userDao.lookupUser(webUserId);
        }
    }
    

    And finally, here's my HelloWorldController:

    package com.saers.view.web.controller;
    
    import com.saers.data.entities.User;
    import com.saers.business.UserService;
    
    import org.springframework.web.servlet.mvc.*;
    import org.springframework.web.servlet.*;
    import javax.servlet.http.*;
    import org.apache.commons.logging.*;
    
    
    
    public class HelloWorldController extends AbstractController {
    
      protected final Log logger = LogFactory.getLog(getClass());
    
      @Override
      public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
        logger.info("Get bean");
        User user = userService.lookupUser("helloUser");
        logger.info("Found out that this user was last changed " + user.getName());
        logger.info("Return View");
        ModelAndView mv = new ModelAndView("HelloWorld.jsp", "user", user);
        return mv;
      }
    
      private UserService userService = null;
      public void setUserService(UserService userService) {
          this.userService = userService;
      }
    
    }
    

    I hope you have some good tips I can use :-) If there's anything else in the code you feel that I'm doing the wrong/non-spring way, I would love to hear about that as well.

    Cheers

    Nik