2011-02-25 9 views
8

Soy nuevo en Spring y estaba intentando crear una aplicación web con la siguiente pila: Apache Tomcat 7, MySQL, Spring MVC, Hibernate 3 con anotaciones JPA.Spring + Hibernate con anotaciones: Ninguna sesión de Hibernate vinculada al thread

Estoy tratando de aprender siguiendo el libro "Primavera en acción, tercera edición" de Craig Walls.

Primero, quería crear una página que muestra algunas entradas que agregué manualmente a mi base de datos, pero parece que mi aplicación no es capaz de crear/recuperar ninguna sesión de Hibernate de mi SessionFactory. Aquí está mi raíz rastro causa pila:

exception 

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722) 

root cause 

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 
    org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63) 
    org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687) 
    com.nbarraille.www.dao.HibernateContactDAO.listContact(HibernateContactDAO.java:27) 
    com.nbarraille.www.controllers.HomeController.showHomePage(HomeController.java:24) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:613) 
    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176) 
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426) 
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722) 

Y aquí están mis clases interesadas/Los archivos de configuración:

Mi HibernateDAO:

@Repository 
public class HibernateContactDAO implements ContactDAO { 

    private SessionFactory sessionFactory; 

    @Autowired 
    public HibernateContactDAO(SessionFactory sessionFactory){ 
     this.sessionFactory = sessionFactory; 
    } 

    public void addContact(Contact contact) { 
     sessionFactory.getCurrentSession().save(contact); 
    } 

    public List<Contact> listContact() { 
     @SuppressWarnings("unchecked") 
     List<Contact> cl = sessionFactory.getCurrentSession().createQuery("from Contact").list(); 
     return cl; 
    } 

    public void removeContact(Integer id) { 
     Contact contact = (Contact) sessionFactory.getCurrentSession().load(Contact.class, id); 
     if (null != contact) { 
      sessionFactory.getCurrentSession().delete(contact); 
     } 

    } 
} 

Mi clase de contacto:

@Entity 
@Table(name="contacts") 
public class Contact implements Serializable { 
    private static final long serialVersionUID = -5389913432051078273L; 

    @Id 
    @Column(name="id") 
    @GeneratedValue 
    private int id; 

    @Column(name="first_name") 
    private String firstname; 

    @Column(name="last_name") 
    private String lastname; 

    @Column(name="email") 
    private String email; 

    @Column(name="telephone") 
    private String telephone; 


    // Setters/Getters 
} 

Mi clase de controlador:

@Controller 

    public class HomeController { 

     private ContactDAO contactDAO; // I know I should pass through a service instead of accessing my DAO directly, and I usually do, but I skipped it here to simplify and try to locate the problem 

     @Inject 
     public HomeController(ContactDAO contactDAO){ 
      this.contactDAO = contactDAO; 
     } 

     @RequestMapping({"/", "/home"}) 
     public String showHomePage(Map<String,Object> model){ 
      model.put("contacts", contactDAO.listContact()); 
      return "index"; 
     } 
    } 

Aquí es mi Contexto archivo de datos de configuración:

<bean id="DBpropertyConfigurer" 
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="location" value="/WEB-INF/jdbc.properties" /> 
    </bean> 

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <property name="url" value="jdbc:mysql://localhost:3306/nbarraille" /> 
    <property name="username" value="root" /> 
    <property name="password" value="password" /> 
    </bean> 
    <bean id="sessionFactory" 
     class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
     <property name="dataSource" ref="dataSource" /> 
     <property name="packagesToScan" value="com.nbarraille.www.core" /> 
     <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
       <prop key="hibernate.show_sql">true</prop> 
      </props> 
     </property> 
    </bean> 

    <!-- Adds an advisor to any bean annotated with @Repository so that any platform-specific exception 
     are caught and then rethrown as one of Spring's unchecked data access exceptions --> 
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

Aquí es mi config Dispatcher Servlet:

<mvc:resources mapping="/resources/**" 
        location="/resources/" /> 

<mvc:annotation-driven /> 

<context:component-scan base-package="com.nbarraille.www" /> 

<bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver" /> 

<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> 
     <property name="definitions"> 
      <list> 
       <value>/WEB-INF/tiles-def.xml</value> 
      </list> 
     </property> 
    </bean> 

    <bean id="messageSource" 
     class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
     <property name="basename" value="classpath:messages" /> 
     <property name="defaultEncoding" value="UTF-8"/> 
    </bean> 

    <bean id="localeChangeInterceptor" 
     class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
     <property name="paramName" value="lang" /> 
    </bean> 

    <bean id="localeResolver" 
     class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> 
     <property name="defaultLocale" value="en"/> 
    </bean> 

Y, por último, aquí está mi archivo web.xml:

<servlet> 
    <servlet-name>nbarraille</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>nbarraille</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> 

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/nbarraille-service.xml 
     /WEB-INF/nbarraille-data.xml 
     /WEB-INF/nbarraille-security.xml 
    </param-value> 
</context-param> 

Respuesta

12

Parece que todavía no tiene la transacción configurada ... puede agregar lo siguiente en su Contexto de datos de configuración fichero: -

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<tx:advice id="txAdvice"> 
    <tx:attributes> 
     <tx:method name="*" propagation="REQUIRED" /> 
    </tx:attributes> 
</tx:advice> 

<aop:config> 
    <aop:advisor pointcut="execution(* YOUR.PACKAGE..*.*(..))" advice-ref="txAdvice" /> 
</aop:config> 

Cambio YOUR.PACKAGE a su verdadero nombre del paquete, por ejemplo: -

execution(* com.project..*.*(..)) 

Ésta es una forma perezosa para envolver todos sus métodos en su proyecto con transacción.

Por cierto, si se va a consultar con pereza sus objetos de dominio de Hibernate (ex: parent.getChildren()) en su punto de vista, entonces yo sugeriría altamente añadir esto en su web.xml: -

<filter> 
    <filter-name>hibernateFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>hibernateFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Este filtro extiende la sesión de Hibernate a la vista.

+1

Correcto. Quizás también considere usar la notación '@ Transactional' en su DAO como una alternativa a aop. –

+0

Al agregar la cosa de filtro me liberé de ese error, gracias. ¿Qué es exactamente lo que está haciendo? No agregué el soporte de transacción aún, ya que no sé de qué se trata. – nbarraille

+1

@nbarraille: ese filtro garantiza que su capa de visualización tenga acceso a la sesión de Hibernate. Tenga en cuenta que necesitará este filtro ** Y ** transacción configurada si desea que sus cosas funcionen correctamente. Tener este filtro no significa que tenga una transacción incluida en cada solicitud del usuario. Lea esto para obtener más información: http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html – limc

0

Por lo que vale la pena ... funcionado en esto así, después de buscar mucho tuvo que modificar parte de web.xml:

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

... específicamente tuvo que establecer singleSession a verdadera

0

Tengo el mismo problema hoy.Está conectado con la concepción de unidad de trabajo hibernate y la transacción db. Así que hablando en breve. Si usa framework spring, tiene un administrador de transacciones propio e impelementación de fábrica de sesión. Pero si desea usarlo, recuerde configurarlo, pero también el orden correcto de la adnotación. Su servicio debe ser @Transactional, su DAO debe ser @Repository y DAO usar @Entity beans. Por lo tanto, si utiliza la implementación de primavera del gerente de transacciones, debe usar su servicio transaccional en su controlador;) es bastante simple y en su caso, realiza sessionfactory.getCurrentSession() para obtener la sesión;)

Cuestiones relacionadas