Hibernate / Spring3: не удалось инициализировать прокси - нет сеанса - PullRequest
4 голосов
/ 30 июля 2009

Я новичок в Spring, поэтому я установил Spring 3.0M3 на сервер Tomcat на моем Mac, сделал проект Eclipse, выполнил Hello World, а затем хотел сохранить объект в Hibernate. Я создал таблицу User на своем MySQL-сервере, создал объект User со всеми методами получения и установки (я бы очень хотел, чтобы Java брала здесь очередь из Objective-C и добавляла динамические свойства. Слишком много помех в коде сгенерированным кодом свойства) создал объект UserDao для поиска и сохранения пользователя и создал конфигурацию компонента. Это идет довольно хорошо ... за исключением того, что сеанс не инициализирован. Почему это? Я могу получить доступ к базе данных с этого компьютера, используя эти учетные данные.

Я понимаю, что это, вероятно, просто нормальный материал для начинающих, но все, что я обнаружил в ошибке, когда гуглил, было то, что люди теряли сессии на полпути при переходе из Hibernate 2 в 3. Я не переходил, и, насколько я могу судить, сессия никогда не проводится.

Вот моя ошибка:

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)

Вот мой конфиг сервлета для связанных bean-компонентов:

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

Вот мой класс пользователя:

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

А вот и мой 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;
    }
}

Вот мой интерфейс UserService

public interface UserService {

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

и его реализация:

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

И, наконец, вот мой 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;
  }

}

Надеюсь, у вас есть несколько полезных советов, которые я могу использовать :-) Если в коде есть что-то еще, вы чувствуете, что я поступаю неправильно / не по-весеннему, я бы тоже хотел об этом услышать.

Приветствия

Nik

Ответы [ 2 ]

8 голосов
/ 30 июля 2009

Ваша трассировка стека не совпадает с примером кода, который вы опубликовали для UserDao. Трассировка говорит, что вы звоните HibernateTemplate.initialize() из UserDao.lookupUser(), но ваш пример кода не делает ничего подобного (также не следует, initialize() не должен вызываться здесь).

Edit: OK, с новой трассировкой стека, кажется, проблема в том, что вы просто вызываете hibernateTemplate.load(), который следует использовать только в определенных обстоятельствах (и это не один из них). Вы, вероятно, должны звонить hibernateTemplate.get().

3 голосов
/ 30 июля 2009

Когда вы делаете вызов dao, вы «загружаете» объект. Load не попадает в базу данных, она возвращает прокси на объект, так что база данных попадает только тогда, когда это абсолютно необходимо.

Вы не начали транзакцию до загрузки - загрузка работает, потому что у вас включено чтение без транзакций (по умолчанию включено). Это не говорит, извините, нет транзакции (это в основном создает одну для вас, чтобы сделать чтение, которое заканчивается немедленно).

Таким образом, когда вы выполняете getName, когда ему действительно нужно попасть в базу данных, он сообщает вам «нет сеанса», потому что сеанс, который загрузил этот объект, закрыт (он был закрыт немедленно).

Что нужно сделать, чтобы исправить это, так это запустить транзакцию в начале вызова сервлета и завершить ее в конце - таким образом, когда вы сделаете getName, сессия все еще будет доступна.

Весной, наверное, есть что-то для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...