Results 1 to 6 of 6

Thread: No Hibernate Session bound to thread on save, update and delete

  1. #1
    Join Date
    Oct 2010
    Posts
    10

    Default No Hibernate Session bound to thread on save, update and delete

    I have a "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here" exception only when I try to perform a not read-only transaction.
    The application consists of 2 Liferay portlets, one for the administration of surveys (igiSurvey), one to take a survey (igiTakeSurvey). I use annotations.

    Stacktrace
    Code:
    DEBUG [http-8080-1] (OpenSessionInViewInterceptor.java:154) - Opening single Hibernate Session in OpenSessionInViewInterceptor
    DEBUG [http-8080-1] (SessionFactoryUtils.java:316) - Opening Hibernate Session
    DEBUG [http-8080-1] (SessionImpl.java:220) - opened session at timestamp: 13105723712
    DEBUG [http-8080-1] (DispatcherPortlet.java:723) - Render phase found exception caught during action phase - rethrowing it
    DEBUG [http-8080-1] (OpenSessionInViewInterceptor.java:212) - Closing single Hibernate Session in OpenSessionInViewInterceptor
    DEBUG [http-8080-1] (SessionFactoryUtils.java:789) - Closing Hibernate Session
    ERROR [http-8080-1] (FrameworkPortlet.java:559) - Could not complete request
    org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
            at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
            at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:542)
            at it.infn.grid.liferay.survey.modules.core.dao.impl.GenericDaoHibernate.findById(GenericDaoHibernate.java:179)
            at it.infn.grid.liferay.survey.modules.survey.service.impl.SurveyServiceImpl.findById(SurveyServiceImpl.java:127)
            at it.infn.grid.liferay.survey.modules.survey.controller.EditSurveyController.getCommandObject(EditSurveyController.java:104)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:162)
            at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:358)
            at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.doHandle(AnnotationMethodHandlerAdapter.java:345)
            at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.handleAction(AnnotationMethodHandlerAdapter.java:280)
            at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:641)
            at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:519)
            at org.springframework.web.portlet.FrameworkPortlet.processAction(FrameworkPortlet.java:460)
            at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:70)
            at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:48)
    My configuration
    web.xml (selected fragments)
    Code:
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/applicationContext.xml
            </param-value>
    	</context-param>
    
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<servlet>
    		<servlet-name>ViewRendererServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>ViewRendererServlet</servlet-name>
    		<url-pattern>/WEB-INF/servlet/view</url-pattern>
    	</servlet-mapping>
    applicationContext.xml (fragments
    Code:
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource" />
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                    <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
    ${hibernate.current_session_context_class}</prop>-->
                    <prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
                </props>
            </property>
            <property name="annotatedClasses">
                <list>
                    ... (model classes)
                </list>
            </property>
        </bean>
    
        <bean name="openSessionInViewInterceptor" class="org.springframework.web.portlet.handler.WebRequestHandlerInterceptorAdapter">
            <constructor-arg>
                <bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
                    <property name="sessionFactory" ref="sessionFactory"/>
                </bean>
            </constructor-arg>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
    
        <tx:annotation-driven transaction-manager="transactionManager" />
    igiSurvey-portlet.xml (fragments)
    Code:
        <context:component-scan base-package="it.infn.grid.liferay.survey.modules.survey" />
    
        <context:component-scan base-package="it.infn.grid.liferay.survey.modules" >
            <context:include-filter type="regex" expression="it.infn.grid.liferay.survey.modules.takesurvey.*Service.*" />
        </context:component-scan>
    
        <!-- It allows us to use @Autowire, @Required and @Qualifier annotations. -->
    	<context:annotation-config />
    
        <bean id="annotationMapper" class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">
            <property name="order" value="10" />
            <property name="interceptors">
                <list>
                    <ref bean="openSessionInViewInterceptor"/>
                </list>
            </property>
        </bean>
    Same content for igiTakeSurvey-portlet.xml

    I have a GenericDaoHibernate implementing GenericDao which is annotated with @Transactional

    Code:
        @Transactional(readOnly = true)
        public T findById(final ID id, final boolean lock) throws DataAccessException {
    but all the other transaction annotations are in the service layer:
    Code:
    @Service(value="surveyService")
    public class SurveyServiceImpl implements SurveyService {
    
        @Transactional(readOnly = true)
        public Survey findById(Long id) {
            ....
        }
    
    @Transactional(readOnly = false)
        public Survey save(Survey survey) {
            ....
        }
    DAOs:
    Code:
    @Repository("surveyDao")
    public class SurveyDaoHibernate extends GenericDaoHibernate<Survey, Long> implements SurveyDao {
    
        @Autowired
        public SurveyDaoHibernate(SessionFactory factory) {
            super(factory);
        }
    
        ....
    }
    Everything was working before I switched to annotating the transactions.
    I read a lot of threads about this exception but no solution has worked for me.

    Thank you!

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    1) Don't set the hibernate.current_session_context_class unless you use JTA
    2) Your tx:annotation-driven is in the root context, whereas your services are detected in a child context (and Bean(Factory)PostProcessor only operate on the applicationcontext they are loaded in not the parent or child)
    3) You use component-scanning make sure you don't scan the same components twice (resulting in 1 transactional and one non transactional service and the latter is probaly going to be used)

    Also please the search as I answered this question numerous times before...
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Oct 2010
    Posts
    10

    Default No solution yet

    Quote Originally Posted by Marten Deinum View Post
    1) Don't set the hibernate.current_session_context_class unless you use JTA
    2) Your tx:annotation-driven is in the root context, whereas your services are detected in a child context (and Bean(Factory)PostProcessor only operate on the applicationcontext they are loaded in not the parent or child)
    3) You use component-scanning make sure you don't scan the same components twice (resulting in 1 transactional and one non transactional service and the latter is probaly going to be used)

    Also please the search as I answered this question numerous times before...
    Thank you for your answer Marten.

    1. That was actually a commented out line as you can see from the closing tag. I left it in by mistake. Sorry for the confusion.

    2. I tried to move the tx:annotation-driven command out of the root context and into each child context. Same error:
    Code:
    15:00:47,807 ERROR [jsp:154] org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    	at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:542)
    	at it.infn.grid.liferay.survey.modules.core.dao.impl.GenericDaoHibernate.findById(GenericDaoHibernate.java:179)
    	at it.infn.grid.liferay.survey.modules.survey.service.impl.SurveyServiceImpl.findById(SurveyServiceImpl.java:127)
    	at it.infn.grid.liferay.survey.modules.survey.controller.EditSurveyController.getCommandObject(EditSurveyController.java:104)
    3. Can I scan components twice but each time in a different application context?
    I need some classes in both portlets.

    Thank you again Marten!

  4. #4
    Join Date
    Oct 2010
    Posts
    10

    Default Current situation

    That's what I modified. From what I understand the 2 web application contexts (igiSurvey-portlet.xml and igiTakeSurvey-portlet.xml) are loaded before the root context (applicationContext.xml). So I configured only the relevant controllers in each of the web application contexts (igiSurvey-portlet.xml shown):
    Code:
        <context:annotation-config />
    
        <context:component-scan base-package="it.infn.grid.liferay.survey.modules.survey" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    and I'm scanning for all services and DAOs in the root context where transaction management is also configured:
    Code:
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
    
        <tx:annotation-driven transaction-manager="transactionManager" />
    
        <context:component-scan base-package="it.infn.grid.liferay.survey.modules" use-default-filters="false">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    Well, now the web application context of the first portlet complains that a service is missing:
    Code:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chooseSurveyController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private it.infn.grid.liferay.survey.modules.survey.service.SurveyService it.infn.grid.liferay.survey.modules.takesurvey.controller.ChooseSurveyController.surveyService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [it.infn.grid.liferay.survey.modules.survey.service.SurveyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=surveyService)}
    In this situation with a root application contexts and 2 contexts associated to 2 portlets, I don't seem to be able to produce a match among the fact that scanning works only in the context it is configured, the fact that controllers need services injected into them (=> I need to load services in web application contexts) and the fact I should not load the same component twice...

  5. #5
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    You don't need to load the services in the web application context you only need them in the root context, because that is shared. You disabled the default filters which basically doesn't scan for anything in your root context. So enable default filters and simply exclude the @Controller (basically the same as you have no but without the use-default-filters). And the web context aren't loaded before the root context (if that is the case there is something really wrong with your setup/configuration).
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  6. #6
    Join Date
    Oct 2010
    Posts
    10

    Default Solved

    I finally solved my exception and got more insight into spring transaction management.
    Marten, I didn't fully understand your suggestion #2 upon a first read but basically the point was the one explained on this note in the reference documentation: "<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in."
    Now in my root applicationContext.xml I have

    - a component scan for all common beans;
    - data source definition using DriverManagerDataSource
    - session factory definition using AnnotationSessionFactoryBean
    - open session in view interceptor
    - transaction manager definition using the HibernateTransactionManager
    - activation of annotation-based transactional behavior (tx:annotation-driven)

    The other 2 application contexts for the 2 portlets have:

    - activation of annotation-based transactional behavior (tx:annotation-driven)
    - <context:annotation-config />
    - a component scan for the local beans (Controllers);
    - an annotation mapper (DefaultAnnotationHandlerMapping) using the openSessionInViewInterceptor

    and everything works again. That's why it was working when I wasn't using annotations for the transaction configuration.
    Thank you Marten for your time.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •