【问题标题】:"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:&lt;bean id="decisionsRep" class="com.asg.tciclientadapters.webdav.dal.RetentionController"/&gt; 并且所有类都通过 @autowired 字段或构造函数参数接收 RetentionController(这导致类,它是由 @autowired 获得的)

标签: java hibernate spring transactions


【解决方案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 依赖项中使用的版本。

    【讨论】:

      猜你喜欢
      • 2011-10-25
      • 2012-02-03
      • 2011-06-08
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多