|
|
HibernateException: No Hibernate Session bound to thread
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 lt;tx:annotation-driven/gt; 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:Code: 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
I have the following application context configuration file:Code: lt;?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?gt; lt;beans xmlns=quot;schema/beansquot; xmlns:aop=quot;schema/aopquot; xmlns:flex=quot;schema/flexquot; xmlns:tx=quot;schema/txquot; xmlns:xsi=quot;2001/XMLSchema-instancequot; xsi:schemaLocation=quot;schema/beans schema/beans/spring-beans-2.5.xsd schema/flex schema/flex/spring-flex-1.0.xsd schema/tx schema/tx/spring-tx-2.0.xsdquot;gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;!-- load values used for bean properties --gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;bean class=quot;org..beans.factory.config.PropertyPlaceholderConfigurerquot;gt;lt;property name=quot;locationsquot;gt; lt;valuegt;applicationContext.propertieslt;/valuegt;lt;/propertygt; lt;/beangt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;!-- DataSource where objects will be persisted --gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;bean id=quot;dataSourcequot; class=quot;org..jdbc.datasource.DriverManagerDataSourcequot;gt;lt;property name=quot;usernamequot; value=quot;${datasource.username}quot; /gt;lt;property name=quot;passwordquot; value=quot;${datasource.password}quot; /gt;lt;property name=quot;uclquot; value=quot;${datasource.ucl}quot; /gt;lt;property name=quot;driverClassNamequot; value=quot;${datasource.driver}quot; /gt; lt;/beangt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;!-- Factory bean for Hibernate Sessions --gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;bean id=quot;hibernateSessionFactoryquot; class=quot;org..orm.hibernate3.annotation.AnnotationSessionFactoryBeanquot;gt;lt;property name=quot;dataSourcequot; ref=quot;dataSourcequot; /gt;lt;property name=quot;annotatedClassesquot;gt; lt;listgt; lt;valuegt;gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlDailyAvglt;/valuegt; lt;/listgt;lt;/propertygt;lt;property name=quot;hibernatePropertiesquot;gt; lt;propsgt; lt;prop key=quot;hibernate.dialectquot;gt;${hibernate.dialect}lt;/propgt; lt;prop key=quot;hibernate.hbm2ddl.autoquot;gt;${hibernate.hbm2ddlauto}lt;/propgt; lt;/propsgt;lt;/propertygt; lt;/beangt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;!-- Transaction Manager bean --gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;bean id=quot;transactionManagerquot; class=quot;org..orm.hibernate3.HibernateTransactionManagerquot;gt;lt;property name=quot;sessionFactoryquot; ref=quot;hibernateSessionFactoryquot; /gt; lt;/beangt; lt;tx:annotation-driven transaction-manager=quot;transactionManagerquot; /gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;!-- DAO for ESRL daily average objects --gt; lt;!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --gt; lt;bean id=quot;esrlDailyAvgDaoquot; class=quot;gov.noaa.ncdc.cmb.esrl.domain.dao.EsrlDailyAvgDaoHibernateImplquot;gt;lt;property name=quot;sessionFactoryquot; ref=quot;hibernateSessionFactoryquot; /gt;lt;property name=quot;persistentClassquot; value=quot;gov.noaa.ncdc.cmb.esrl.domain.entity.EsrlDailyAvgquot; /gt; lt;/beangt; lt;/beansgt;
The generic DAO class (from which the DAO being used in my program is extended) looks like this:Code: public class GenericDaoHibernateImpllt;T extends PersistentEntitylt Kgt;, PK extends Serializablegt; implements GenericDaolt;T, PKgt; { private SessionFactory sessionFactory; private Classlt;Tgt; persistentClass; protected String getCanonicalPersistentClassName() {return persistentClass.getCanonicalName(); } /** * Gets the current Hibernate Session object. * * @return */ protected Session getCurrentSession() {return sessionFactory.getCurrentSession(); } /* * (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 Listlt;Tgt; findAll() {return getCurrentSession().createQuery(quot;from quot; + persistentClass.getName()).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); } /* * (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 = quot;Failed to save the object.quot;; log.error(errorMessage, ex); throw new RuntimeException(errorMessage, ex);} } /** * Setter for the persistentClass property. * * @param persistentClass */ public void setPersistentClass(final Classlt;Tgt; 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:
Code: // load the Spring application context, get the DAOs ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[] { quot;dailyAveragingApplicationContext.xmlquot; }); esrlDailyAvgDao = (EsrlDailyAvgDao) applicationContext.getBean(quot;esrlDailyAvgDaoquot;); esrlObservationsDao = (EsrlObservationsDao) applicationContext.getBean(quot;esrlObservationsDaoquot;);
And the exception is encountered when I try to save an entity:Code: esrlDailyAvgDao.saveOrUpdate(esrlDailyAvg);
The DAO class itself uses the Transactional annotation:
Code: @Transactional public class EsrlDailyAvgDaoHibernateImpl extends GenericDaoHibernateImpllt;EsrlDailyAvg, Longgt; implements EsrlDailyAvgDao
The exception stack trace looks like this:
Code: 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..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..aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) at org..aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:196) at $Proxy19.saveOrUpdate(Unknown Source) at gov.noaa.ncdc.cmb.esrl.ingest.EsrlDailyAvgProcessor.main(EsrlDailyAvgProcessor.java:469)
Can anyone suggest where I've gone wrong? Thanks in advance for your help.
--James
Maybe you should better extend your GenericDao from Spring's HibernateDaoSupport class. By using the helper methods like getHibernateTemplate().merge(entity) Spring does all the overhead like opening and closing the session.
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. |
|