web-dev-qa-db-fra.com

Aucune session Hibernate liée au thread, et la configuration n'autorise pas la création d'une session non transactionnelle ici

J'obtiens cette exception lorsque j'appelle une méthode DAO qui utilise SessionFactory.getCurrentSession(). La classe DAO est annotée avec @Transactional et j'ai aussi <tx:annotation-driven/> déclaré dans le fichier de configuration du contexte d'application.

Je peux appeler mes méthodes DAO qui effectuent des requêtes HQL, mais chaque fois que j'appelle une méthode DAO qui obtient d'abord la session Hibernate, je rencontre cette exception:

SEVERE: Failed to save the object.
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:622)
    at gov.noaa.ncdc.cmb.persistence.dao.GenericDaoHibernateImpl.getCurrentSession(GenericDaoHibernateImpl.Java:56)
    at gov.noaa.ncdc.cmb.persistence.dao.GenericDaoHibernateImpl.saveOrUpdate(GenericDaoHibernateImpl.Java:187)

J'ai le fichier de configuration de contexte d'application suivant:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:flex="http://www.springframework.org/schema/flex"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/flex
                           http://www.springframework.org/schema/flex/spring-flex-1.0.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  load values used for bean properties  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <value>applicationContext.properties</value>
        </property>
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  DataSource where objects will be persisted  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="${datasource.username}" />
        <property name="password" value="${datasource.password}" />
        <property name="url" value="${datasource.url}" />
        <property name="driverClassName" value="${datasource.driver}" />
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!-- Factory bean for Hibernate Sessions -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlDailyAvg</value>
                <value>gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlObservations</value>
                <value>gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlStation</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
                <prop key="hibernate.jdbc.batch_size">50</prop>
                <prop key="hibernate.query.substitutions">true 1, false 0</prop>
                <prop key="hibernate.max_fetch_depth">6</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddlauto}</prop>
                <prop key="hibernate.cache.use_second_level_cache">${hibernate.use_second_level_cache}</prop>
            </props>
        </property>
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  Transaction Manager bean  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="hibernateSessionFactory" />
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  enable the configuration of transactional behavior based on annotations  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <tx:annotation-driven transaction-manager="transactionManager" />


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  DAO for ESRL Station objects  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="esrlStationDao" class="gov.noaa.ncdc.cmb.esrl.domain.dao.EsrlStationDaoHibernateImpl">
        <property name="sessionFactory" ref="hibernateSessionFactory" />
        <property name="persistentClass" value="gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlStation" />
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  DAO for ESRL Observations objects  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="esrlObservationsDao" class="gov.noaa.ncdc.cmb.esrl.domain.dao.EsrlObservationsDaoHibernateImpl">
        <property name="sessionFactory" ref="hibernateSessionFactory" />
        <property name="persistentClass" value="gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlObservations" />
    </bean>


    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--  DAO for ESRL daily average objects  -->
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <bean id="esrlDailyAvgDao" class="gov.noaa.ncdc.cmb.esrl.domain.dao.EsrlDailyAvgDaoHibernateImpl">
        <property name="sessionFactory" ref="hibernateSessionFactory" />
        <property name="persistentClass" value="gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlDailyAvg" />
    </bean>


</beans> 

La classe DAO générique (à partir de laquelle le DAO utilisé dans mon programme est étendu) ressemble à ceci:

package gov.noaa.ncdc.cmb.persistence.dao;

import gov.noaa.ncdc.cmb.persistence.entity.PersistentEntity;
import Java.io.Serializable;
import Java.util.Collection;
import Java.util.Date;
import Java.util.List;
import org.Apache.commons.logging.Log;
import org.Apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;

/**
 * This class is an implementation of GenericDao<T, PK> using Hibernate.
 */
public class GenericDaoHibernateImpl<T extends PersistentEntity<PK>, PK extends Serializable>
    implements GenericDao<T, PK>
{
    private SessionFactory sessionFactory;

    static private Log log = LogFactory.getLog(GenericDaoHibernateImpl.class);

    private Class<T> persistentClass;

    /**
     * Can be used within subclasses as a convenience method.
     * 
     * @param criterionList the criteria to find by
     * @return the list of elements that match the specified criteria
     */
    protected List<T> findByCriteria(final List<Criterion> criterionList)
    {
        Criteria criteria = getCurrentSession().createCriteria(persistentClass);
        for (Criterion criterion : criterionList)
        {
            criteria.add(criterion);
        }
        return criteria.list();
    }

    protected String getCanonicalPersistentClassName()
    {
        return persistentClass.getCanonicalName();
    }

    /**
     * Gets the current Hibernate Session object.
     * 
     * @return
     */
    protected Session getCurrentSession()
    {
        return sessionFactory.getCurrentSession();
    }

    /*
     * This method only provided for interface compatibility.  Not recommended for use with large batches 
     * (this is an inefficient implementation, and it's somewhat difficult to perform batch operations with Hibernate).
     * 
     * (non-Javadoc)
     * @see gov.noaa.ncdc.cmb.persistence.dao.GenericDao#batchInsert(Java.util.Collection)
     */
    @Override
    public int[] batchInsert(final Collection<T> entityCollection)
    {
        int[] updateCounts = new int[entityCollection.size()];
        int i = 0;
        for (T entity : entityCollection)
        {
            try
            {
                saveOrUpdate(entity);
                updateCounts[i] = 1;
                i++;
            }
            catch (Exception ex)
            {
                clear();
                throw new RuntimeException(ex);
            }
        }
        flush();
        clear();

        return updateCounts;
    }

    /*
     * This method only provided for interface compatibility.  Not recommended for use with large batches 
     * (this is an inefficient implementation, and it's somewhat difficult to perform batch operations with Hibernate).
     * 
     * (non-Javadoc)
     * @see gov.noaa.ncdc.cmb.persistence.dao.GenericDao#batchUpdate(Java.util.Collection)
     */
    @Override
    public int[] batchUpdate(final Collection<T> entityCollection)
    {
        return batchInsert(entityCollection);
    }

    /**
     * Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do
     * not close open iterators or instances of ScrollableResults.
     */
    public void clear()
    {
        getCurrentSession().clear();
    }

    /*
     * (non-Javadoc)
     * @see gov.noaa.ncdc.cmb.persistence.dao.GenericDao#delete(gov.noaa.ncdc.cmb.persistence.entity.PersistentEntity)
     */
    @Override
    public void delete(final T persistentObject)
    {
        getCurrentSession().delete(persistentObject);
    }

    /*
     * (non-Javadoc)
     * @see gov.noaa.ncdc.cmb.persistence.dao.GenericDao#findAll()
     */
    @Override
    public List<T> findAll()
    {
        return getCurrentSession().createQuery("from " + persistentClass.getName()).list();
    }

    /**
     * Finds a collection of entity objects which match to the example instance, minus any specified properties which should be excluded from the matching.
     * 
     * @param exampleInstance
     * @param excludeProperty
     * @return
     */
    public List<T> findByExample(final T exampleInstance,
                                 final String[] excludeProperty)
    {
        Criteria criteria = getCurrentSession().createCriteria(persistentClass);
        Example example = Example.create(exampleInstance);
        if (excludeProperty != null)
        {
            for (String exclude : excludeProperty)
            {
                example.excludeProperty(exclude);
            }
        }
        criteria.add(example);
        return criteria.list();
    }

    /*
     * (non-Javadoc)
     * @see com.Sun.cloud.lifecycle.core.persistence.dao.GenericDao#findById(Java.io.Serializable)
     */
    @Override
    public T findById(final PK id)
    {
        return (T) getCurrentSession().load(persistentClass, id);
    }

    /**
     * Force this session to flush. Must be called at the end of a unit of work, before commiting the transaction and
     * closing the session (depending on flush-mode, Transaction.commit() calls this method).
     * 
     * Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.
     */
    public void flush()
    {
        getCurrentSession().flush();
    }

    /*
     * (non-Javadoc)
     * @see gov.noaa.ncdc.cmb.persistence.dao.GenericDao#saveOrUpdate(gov.noaa.ncdc.cmb.persistence.entity.PersistentEntity)
     */
    @Override
    public T saveOrUpdate(final T entity)
    {
        try
        {
            entity.setUpdatedDate(new Date());
            getCurrentSession().saveOrUpdate(entity);
            return entity;
        }
        catch (Exception ex)
        {
            String errorMessage = "Failed to save the object.";
            log.error(errorMessage, ex);
            throw new RuntimeException(errorMessage, ex);
        }
    }

    /**
     * Setter for the persistentClass property.
     * 
     * @param persistentClass
     */
    public void setPersistentClass(final Class<T> persistentClass)
    {
        this.persistentClass = persistentClass;
    }

    /**
     * Property setter.
     * 
     * @param sessionFactory
     */
    public void setSessionFactory(final SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

}

Mon application obtient le DAO du contexte d'application:

// load the Spring application context, get the DAOs
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[] { "dailyAveragingApplicationContext.xml" });
esrlDailyAvgDao = (EsrlDailyAvgDao) applicationContext.getBean("esrlDailyAvgDao");
esrlObservationsDao = (EsrlObservationsDao) applicationContext.getBean("esrlObservationsDao");

Et l'exception se produit lorsque j'essaie d'enregistrer une entité:

esrlDailyAvgDao.saveOrUpdate(esrlDailyAvg);

La classe DAO elle-même utilise l'annotation transactionnelle:

@Transactional
public class EsrlDailyAvgDaoHibernateImpl
    extends GenericDaoHibernateImpl<EsrlDailyAvg, Long>
    implements EsrlDailyAvgDao

La trace de la pile d'exceptions ressemble à ceci:

SEVERE: Failed to save the object.
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:622)
    at gov.noaa.ncdc.cmb.persistence.dao.GenericDaoHibernateImpl.getCurrentSession(GenericDaoHibernateImpl.Java:56)
    at gov.noaa.ncdc.cmb.persistence.dao.GenericDaoHibernateImpl.saveOrUpdate(GenericDaoHibernateImpl.Java:187)
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at Java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:309)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:196)
    at $Proxy19.saveOrUpdate(Unknown Source)
    at gov.noaa.ncdc.cmb.esrl.ingest.EsrlDailyAvgProcessor.main(EsrlDailyAvgProcessor.Java:469)
49
James Adams

J'ai résolu ce problème en ajoutant @Transactional à la classe d'implémentation de base/générique Hibernate DAO (la classe parente qui implémente la méthode saveOrUpdate () héritée par le DAO que j'utilise dans le programme principal), c'est-à-dire la @Transactional doit être spécifié sur la classe réelle qui implémente la méthode. Mon hypothèse était plutôt que si je déclarais @Transactional sur la classe enfant, il comprenait toutes les méthodes héritées par la classe enfant. Cependant, il semble que le @Transactional l'annotation ne s'applique qu'aux méthodes implémentées dans une classe et non aux méthodes héritées par une classe.

45
James Adams

J'ai eu l'erreur suivante:

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)

J'ai corrigé cela en modifiant mon fichier de propriétés d'hibernation

hibernate.current_session_context_class=thread

Mon code et mon fichier de configuration comme suit

session =  getHibernateTemplate().getSessionFactory().getCurrentSession();

session.beginTransaction();

session.createQuery(Qry).executeUpdate();

session.getTransaction().commit();

sur le fichier de propriétés

hibernate.dialect=org.hibernate.dialect.MySQLDialect

hibernate.show_sql=true

hibernate.query_factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory

hibernate.current_session_context_class=thread

sur le fichier de cofiguration

<properties>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>         
<prop key="hibernate.query.factory_class">${hibernate.query_factory_class}</prop>       
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
</props>
</property>
</properties>

Merci,
Ashok

12
Ashok

après avoir ajouté la propriété:

<prop key="hibernate.current_session_context_class">thread</prop> Je reçois l'exception comme:

org.hibernate.HibernateException: createQuery is not valid without active transaction
org.hibernate.HibernateException: save is not valid without active transaction.

je pense donc que la définition de cette propriété n'est pas une bonne solution.

enfin, je résout le problème "Aucune session de mise en veille prolongée liée au thread":

1.<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
2.ajouter <tx:annotation-driven /> vers servlet-context.xml ou dispatcher-servlet.xml
3.ajoutez @Transactional après @Service et @Repository

7
didihe1988

J'ai eu le même problème aujourd'hui. Pendant que je cherchais ici une solution, j'ai fait une erreur stupide qui est au lieu d'importer

import org.springframework.transaction.annotation.Transactional;

sans le savoir j'ai importé

import javax.transaction.Transactional;

Après l'avoir changé, tout a bien fonctionné.

Alors pensé au partage, si quelqu'un fait la même erreur.

2
Hema

Chaque fois que vous rencontrerez une erreur ci-dessous, suivez-la.

org.hibernate.HibernateException: aucune session Hibernate liée au thread, et la configuration n'autorise pas la création d'une session non transactionnelle ici sur org.springframework.orm.hibernate3.SpringSessionContext.currentSession (SpringSessionContext.Java:63)

Mettez un @Transactional annotation pour chaque méthode d'implémentation des classes.

1

Vous pouvez avoir @Transactional dans la classe enfant, mais vous devez remplacer chacune des méthodes et appeler la super méthode afin de la faire fonctionner.

Exemple:

@Transactional(readOnly = true)
public class Bob<SomeClass> {
   @Override
   public SomeClass getValue() {
       return super.getValue();
   }
}

Cela lui permet de le configurer pour chacune des méthodes pour lesquelles il est nécessaire.

1
ScrappyDev

As-tu org.springframework.orm.hibernate3.support.OpenSessionInViewFilter configuré dans la webapp web.xml (en supposant que votre application est une webapp), ou encapsuler les appels en conséquence?

1
mindas

Tu es absent <context:annotation-config /> à partir de votre contexte printanier afin que les annotations ne soient pas analysées!

0
rjsang