I am getting this exception when I call a DAO method which uses SessionFactory.getCurrentSession()
. The DAO class is annotated with @Transactional
and I also have <tx:annotation-driven/>
declared in the application context configuration file.
I can call my DAO methods which perform HQL queries, but whenever I call a DAO method which first gets the Hibernate session then I run into this 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)
I have the following application context configuration file:
<?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>
The generic DAO class (from which the DAO being used in my program is extended) looks like this:
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; } }
My application gets the DAO from the application context:
// 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");
And the exception is encountered when I try to save an entity:
esrlDailyAvgDao.saveOrUpdate(esrlDailyAvg);
The DAO class itself uses the Transactional annotation:
@Transactional public class EsrlDailyAvgDaoHibernateImpl extends GenericDaoHibernateImpl<EsrlDailyAvg, Long> implements EsrlDailyAvgDao
The exception stack trace looks like this:
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)
Hibernate SessionFactory getCurrentSession Since this session object belongs to the hibernate context, we don't need to close it. Once the session factory is closed, this session object gets closed. Hibernate Session objects are not thread safe, so we should not use it in multi-threaded environment.
hibernate. context. CurrentSessionContext ) and a new configuration parameter ( hibernate. current_session_context_class ) have been added to allow pluggability of the scope and context of defining current sessions.
SessionFactory is an Interface which is present in org. hibernate package and it is used to create Session Object. It is immutable and thread-safe in nature. buildSessionFactory() method gathers the meta-data which is in the cfg Object.
For example: a single transaction could be such a context, hence if the Hibernate Session's lifecycle matches a life of this transaction, the Session could be called contextual, where a single transaction defines such a context . Sometimes this particular case is labeled as a session-per-request model.
I resolved this by adding @Transactional
to the base/generic Hibernate DAO implementation class (the parent class which implements the saveOrUpdate() method inherited by the DAO I use in the main program), i.e. the @Transactional
needs to be specified on the actual class which implements the method. My assumption was instead that if I declared @Transactional
on the child class then it included all of the methods that were inherited by the child class. However it seems that the @Transactional
annotation only applies to methods implemented within a class and not to methods inherited by a class.
I got the following error:
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)
I fixed this by changing my hibernate properties file
hibernate.current_session_context_class=thread
My code and configuration file as follows
session = getHibernateTemplate().getSessionFactory().getCurrentSession(); session.beginTransaction(); session.createQuery(Qry).executeUpdate(); session.getTransaction().commit();
on properties file
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
on cofiguration file
<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>
Thanks,
Ashok
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With