我在调用使用的DAO方法时遇到此异常SessionFactory.getCurrentSession()。DAO类带有注释,@Transactional我也已经<tx:annotation- driven/>在应用程序上下文配置文件中声明了。
SessionFactory.getCurrentSession()
@Transactional
<tx:annotation- driven/>
我可以调用执行HQL查询的DAO方法,但是每当我调用首先获取Hibernate会话的DAO方法时,就会遇到此异常:
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)
我有以下应用程序上下文配置文件:
<?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>
通用DAO类(从中扩展了我的程序中使用的DAO)如下所示:
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; } }
我的应用程序从应用程序上下文获取DAO:
// 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");
当我尝试保存实体时会遇到异常:
esrlDailyAvgDao.saveOrUpdate(esrlDailyAvg);
DAO类本身使用Transactional注释:
@Transactional public class EsrlDailyAvgDaoHibernateImpl extends GenericDaoHibernateImpl<EsrlDailyAvg, Long> implements EsrlDailyAvgDao
异常堆栈跟踪如下所示:
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)
我通过添加@Transactional到基础/通用Hibernate DAO实现类(实现了我在主程序中使用的DAO继承的saveOrUpdate()方法的父类)来解决此问题,即@Transactional需要在实现该类的实际类上指定方法。相反,我的假设是,如果我@Transactional在子类上声明,则它包括子类继承的所有方法。但是,@Transactional注释似乎仅适用于在类内实现的方法,而不适用于由类继承的方法。