“没有绑定到线程的休眠会话”,事务方法中断下一个事务的执行
Posted
技术标签:
【中文标题】“没有绑定到线程的休眠会话”,事务方法中断下一个事务的执行【英文标题】:"No Hibernate Session bound to thread", transactional method breaks execution of the next transaction 【发布时间】:2011-09-19 13:08:46 【问题描述】:我的问题隐藏在课堂上,有两种方法。
@Repository
@Transactional(isolation = Isolation.READ_COMMITTED)
public class RetentionController
@Autowired
private SessionFactory sessionFactory;
...
@Transactional(readOnly = true)
public BaseResource getResource(String pPath)throws ResourceNotFoundException
...
Criteria critDirExists = sessionFactory.getCurrentSession().createCriteria(Directory.class);
critDirExists.add(Restrictions.eq(PATH, pPath));
Directory dir = (Directory) critDirExists.uniqueResult();
...processing results...
@Transactional(readOnly = false)
public void addDirectory(String pPath)
modelValidator.validateDirectoryURI(pPath);
//check if such exists
Criteria critExists = sessionFactory.getCurrentSession().createCriteria(Directory.class);
critExists.add(Restrictions.eq("path", pPath));
...
...
SessionFactory 被正确注入 - 第一个方法正常执行。问题是: addDirectory 在“Criteria critExists = sessionFactory.getCurrentSession().createCriteria(Directory.class);”处抛出“No Hibernate Session bound to thread”,当它在“getResource()”方法之后被调用时。
日志(我添加了标记以查看方法的开始和结束位置:GET RESOURCE: START/END, ADD DIRECTORY: START/END):
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'transactionManager'
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Creating new transaction with name [com.asg.tciclientadapters.webdav.dal.RetentionController.getResource]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Opened new Session [org.hibernate.impl.SessionImpl@1be3bb2] for Hibernate transaction
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@1be3bb2]
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Setting JDBC Connection [jdbc:sqlserver://******\****:****;selectMethod=direct;lastUpdateCount=true;, UserName=*********, Microsoft SQL Server 2005 JDBC Driver] read-only
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Exposing Hibernate transaction as JDBC transaction [jdbc:sqlserver://******\****:****;selectMethod=direct;lastUpdateCount=true;, UserName=*********, Microsoft SQL Server 2005 JDBC Driver]
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@13b8f62] for key [org.apache.commons.dbcp.BasicDataSource@115512] to thread [http-9080-1]
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Bound value [org.springframework.orm.hibernate3.SessionHolder@299629] for key [org.hibernate.impl.SessionFactoryImpl@1429498] to thread [http-9080-1]
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Initializing transaction synchronization
TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] - Getting transaction for [com.asg.tciclientadapters.webdav.dal.RetentionController.getResource]
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'com.asg.tciclientadapters.webdav.aspect.TraceLog#0'
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - ---GET RESOURCE: START
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@299629] for key [org.hibernate.impl.SessionFactoryImpl@1429498] bound to thread [http-9080-1]
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - Getting ILM object: /CADPWebDAV
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - RequestType is MKCOL
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - EmbryoResource was created.
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@299629] for key [org.hibernate.impl.SessionFactoryImpl@1429498] bound to thread [http-9080-1]
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - ---GET RESOURCE: END
TRACE [com.asg.tciclientadapters.webdav.aspect.TraceLog] - RetentionController.getResource(..) Executed at: 78 ms
TRACE [com.asg.tciclientadapters.webdav.aspect.TraceLog] - Method Argument [1]: com.asg.tciclientadapters.webdav.servlet.CADPRequest@10241ae
TRACE [com.asg.tciclientadapters.webdav.aspect.TraceLog] - Method Argument [2]: com.asg.tciclientadapters.webdav.tci.TCIWrapper@1ca203
TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] - Completing transaction for [com.asg.tciclientadapters.webdav.dal.RetentionController.getResource]
TRACE [org.springframework.orm.hibernate3.HibernateTransactionManager] - Triggering beforeCommit synchronization
TRACE [org.springframework.orm.hibernate3.HibernateTransactionManager] - Triggering beforeCompletion synchronization
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Initiating transaction commit
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@1be3bb2]
TRACE [org.springframework.orm.hibernate3.HibernateTransactionManager] - Triggering afterCommit synchronization
TRACE [org.springframework.orm.hibernate3.HibernateTransactionManager] - Triggering afterCompletion synchronization
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Clearing transaction synchronization
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Removed value [org.springframework.orm.hibernate3.SessionHolder@299629] for key [org.hibernate.impl.SessionFactoryImpl@1429498] from thread [http-9080-1]
TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@13b8f62] for key [org.apache.commons.dbcp.BasicDataSource@115512] from thread [http-9080-1]
DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] - Closing Hibernate Session [org.hibernate.impl.SessionImpl@1be3bb2] after transaction
DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - ---ADD DIRECTORY: START
DEBUG [com.asg.tciclientadapters.webdav.dal.RetentionController] - Validation: OK
DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Opening Hibernate Session
DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
ERROR [com.asg.tciclientadapters.webdav.servlet.CADPServlet] - org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Spring配置xml文件:
<context:property-placeholder location="classpath:spring.properties"/>
<context:annotation-config/>
<tx:annotation-driven/>
<aop:aspectj-autoproxy/>
<context:mbean-export/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="$jdbc.driverClassName"
p:url="$jdbc.url"
p:username="$jdbc.username"
p:password="$jdbc.password"/>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource" p:mappingResources="CADPWebDAV_hbm.xml">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">$hibernate.dialect</prop>
<prop key="hibernate.show_sql">$hibernate.show_sql</prop>
<prop key="hibernate.generate_statistics">$hibernate.generate_statistics</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
</props>
</property>
<property name="eventListeners">
<map>
<entry key="merge">
<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
</entry>
</map>
</property>
</bean>'
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
这里是异常的 StackTrace:
[com.asg.tciclientadapters.webdav.servlet.CADPServlet] - org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
[com.asg.tciclientadapters.webdav.servlet.CADPServlet] - org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
[com.asg.tciclientadapters.webdav.servlet.CADPServlet] - org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
[com.asg.tciclientadapters.webdav.servlet.CADPServlet] - com.asg.tciclientadapters.webdav.dal.RetentionController.addDirectory(RetentionController.java:189)
...
【问题讨论】:
您能否添加堆栈跟踪的相关部分,表明异常源自 addDirectory 方法,从日志中看不出它来自 addDirectory 方法。日志与 servlet 相关联。 我添加了抛出异常的 StackTrace - 它肯定是 'addDirectory()'。 你能检查一下你是否在从 spring 检索的对象(context.getBean 或 @Autowired)上调用 addDirectory 方法。从日志看来,addDirectory 调用正在绕过事务代理 - 可能发生的一个原因是该对象不是 Spring bean。您可以设置断点并进行调试 - 检查对象是否真的是代理,如果是,为什么它没有开始新事务。 是的,有 bean:<bean id="decisionsRep" class="com.asg.tciclientadapters.webdav.dal.RetentionController"/>
并且所有类都通过 @autowired 字段或构造函数参数接收 RetentionController(这导致类,它是由 @autowired 获得的)
【参考方案1】:
解决方案是 - 添加到 web.xml:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在那个异常消失之后。
【讨论】:
【参考方案2】:我认为您需要将 addDirectory 方法的 @Transactional 设置更改为以下内容:
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
根据我对 Spring/Hibernate 中事务管理过程如何工作的理解,您当前的设置告诉 hibernate 您将以只读方式执行所有内容,因此当您尝试以非只读方式执行时它爆炸了。我在以下位置找到了支持文档:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-propagation
我假设如果您在 getResource 之前调用 addDirectory 方法,那么您的代码可以正常工作。
【讨论】:
谢谢回复,但是这些方法是被另一个类调用的,所以事务没有传播。我认为它可能在第一种方法之后仍未完成(因此试图在返回结果之前刷新它),但这与 @transactional 注释的本质相矛盾。另外我不得不提到 - 我使用 Spring3.0 很抱歉将您引导至旧文档...我已经更新了我的原始帖子,以便它转到 3.0 版本而不是 2.0。不过我没有任何额外的建议,当你弄清楚时,我希望你能发布解决方案。【参考方案3】:如果 Hibernate 的版本在类属性中不完全一致,就会发生这种情况。
transactionManager 类 org.springframework.orm.hibernateX 必须匹配 SessionFactory 类 org.springframework.orm.hibernateX 版本,也需要支持您在 Maven 依赖项中使用的版本。
【讨论】:
以上是关于“没有绑定到线程的休眠会话”,事务方法中断下一个事务的执行的主要内容,如果未能解决你的问题,请参考以下文章