没有Hibernate Session绑定到线程,configuration不允许在这里创build非事务性的
当我调用一个使用SessionFactory.getCurrentSession()
的DAO方法时,我得到这个exception。 DAO类用@Transactional
注释,我也在应用程序上下文configuration文件中声明了<tx:annotation-driven/>
。
我可以调用执行HQL查询的DAO方法,但每当我调用一个首先获得Hibernate会话的DAO方法时,就会遇到下面的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)
我有以下应用程序上下文configuration文件:
<?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");
当我尝试保存一个实体时遇到exception:
esrlDailyAvgDao.saveOrUpdate(esrlDailyAvg);
DAO类本身使用Transactional注释:
@Transactional public class EsrlDailyAvgDaoHibernateImpl extends GenericDaoHibernateImpl<EsrlDailyAvg, Long> implements EsrlDailyAvgDao
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) 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实现类(实现由我在主程序中使用的DAOinheritance的saveOrUpdate()方法的父类)来解决此问题,即需要在实际上指定@Transactional
实现该方法的类。 我的假设是,如果我在子类声明了@Transactional
,那么它包含了子类inheritance的所有方法。 不过,似乎@Transactional
注解只适用于在类中实现的方法,而不适用于由类inheritance的方法。
我得到了以下错误:
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)
我通过改变我的hibernate属性文件来解决这个问题
hibernate.current_session_context_class=thread
我的代码和configuration文件如下
session = getHibernateTemplate().getSessionFactory().getCurrentSession(); session.beginTransaction(); session.createQuery(Qry).executeUpdate(); session.getTransaction().commit();
在属性文件上
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
在configuration文件上
<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>
谢谢,
阿肖克
在我添加属性后:
<prop key="hibernate.current_session_context_class">thread</prop>
我得到如下exception:
org.hibernate.HibernateException: createQuery is not valid without active transaction org.hibernate.HibernateException: save is not valid without active transaction.
所以我认为设置这个属性不是一个好的解决scheme。
最后我解决了“没有Hibernate会话绑定到线程”的问题:
1. <!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
2.将<tx:annotation-driven />
到servlet-context.xml或dispatcher-servlet.xml
3.在@Service和@Repository之后添加@Transactional
你有org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
configuration在webapp的web.xml
(假设你的应用程序是一个web应用程序),或相应的打包电话?
你从你的spring上下文中缺less<context:annotation-config />
,所以注释没有被扫描!
您可以在子类中拥有@Transactional,但是您必须重写每个方法并调用super方法才能使其工作。
例:
@Transactional(readOnly = true) public class Bob<SomeClass> { @Override public SomeClass getValue() { return super.getValue(); } }
这允许它为每个需要的方法进行设置。
我今天遇到同样的问题。在这里寻找解决办法,我做了一个愚蠢的错误,而不是导入
import org.springframework.transaction.annotation.Transactional;
不知不觉我已经import了
import javax.transaction.Transactional;
改变它一切工作正常。
所以想到分享,如果有人做同样的错误。