2011-02-25 5 views
8

Je suis nouveau à Spring et j'essayais de créer une webapp avec la pile suivante: Apache Tomcat 7, MySQL, Spring MVC, Hibernate 3 avec des annotations JPA. J'essaie d'apprendre en suivant le livre "Spring in Action, Third Edition" par Craig Walls. Tout d'abord, je voulais créer une page qui affiche certaines entrées que j'ai ajoutées manuellement à ma base de données, mais il semble que mon application ne soit pas capable de créer/récupérer une session Hibernate à partir de ma SessionFactory. Voici ma cause racine trace de la pile:Spring + Hibernate avec annotations: No Hibernate Session lié à thread

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) 

Et voici mes concernés Classes/fichiers de configuration:

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

    } 
} 

Ma classe Contact:

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

Mon cours de contrôleur:

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

Voici mon contexte fichier de configuration de données:

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

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

Et enfin, voici mon fichier 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> 

Répondre

12

Vous ne semblez pas encore configuré la transaction ... vous pouvez ajouter ce qui suit dans votre Contexte Les données fichier de configuration: -

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

changement YOUR.PACKAGE à votre nom de package réel, par exemple: -

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

C'est une façon paresseuse pour envelopper toutes vos méthodes dans votre projet avec transaction.

Par ailleurs, si vous allez interroger paresseusement vos objets Hibernate (ex: parent.getChildren()) à votre avis, je vous suggérerais fortement d'ajouter ceci dans votre 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> 

Ce filtre étend la session Hibernate à la vue.

+1

Correct. Peut-être aussi envisager d'utiliser la notation '@ Transactional' sur votre DAO comme alternative à aop. –

+0

Ajout de la chose de filtre m'a débarrassé de cette erreur, merci. Qu'est-ce qu'il fait exactement? Je n'ai pas encore ajouté le support de transaction, car je ne sais pas ce que c'est. – nbarraille

+1

@nbarraille: Ce filtre assure que votre couche de vue a accès à la session Hibernate. Gardez à l'esprit que vous aurez besoin de cette transaction de filtre ** AND ** configurée si vous voulez que votre contenu fonctionne correctement. Avoir ce filtre ne signifie pas que vous avez une transaction à la fin de chaque requête utilisateur. Lisez ceci pour plus d'informations: http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html – limc

0

Pour ce que ça vaut la peine ... courir dans ce aussi bien, après beaucoup dû modifier regardant une partie 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> 

... avait spécifiquement mis singleSession à vrai

0

J'ai le même problème aujourd'hui.Il est connecté avec la conception de l'unité de travail hibernate et la transaction db. Donc, brièvement parlant. Si vous utilisez framework spring, il a son propre gestionnaire de transactions et sa propre implémentation. Mais si vous souhaitez l'utiliser, vous devez vous rappeler de le configurer, mais aussi de l'ordre correct de l'annotation. Votre service doit être @Transactional, votre DAO doit être @Repository et DAO utiliser les beans @Entity. Donc si vous voulez utiliser l'implémentation de Spring du gestionnaire de transactions, vous devriez utiliser votre service transactionnel dans votre contrôleur;) c'est assez simple et dans votre dao vous faites sessionfactory.getCurrentSession() pour obtenir la session;)

Questions connexes