代码之家  ›  专栏  ›  技术社区  ›  RMorrisey

为什么我的(春季)HibernateTransactionManager不在wicket工作?

  •  3
  • RMorrisey  · 技术社区  · 14 年前

    我正在转换一个小的 要使用的web应用程序 小门+春天+冬眠 . 我有一个DAO服务类,带有一个由Spring注入的hibernate SessionFactory。我可以使用会话工厂执行只读操作(默认情况下,autocommit处于启用状态)。我要做的是使用HibernateTransactionManager和@Transactional注释来执行事务操作。

    我定义了一个DAO服务实现,它在标记为@Transactional的方法中使用注入的SessionFactory:

    public class DAO implements IDAO {
     @SpringBean
     private SessionFactory sessionFactory;
    
     public DAO() {
      super();
     }
    
     @Transactional
     public Object execute(SessionUnit sessionUnit) {
      Session sess = sessionFactory.getCurrentSession();
      Object result;
      result = sessionUnit.run(sess);
      sess.flush();
      return result;
     }
    
     public void setSessionFactory(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
     }
    
     @Transactional
     public boolean isObjectPersistent(Object object) {
      return sessionFactory.getCurrentSession().contains(object);
     }
    }
    

    当我试着打电话的时候 isObjectPersistent()

    Caused by: org.hibernate.HibernateException: contains is not valid without active transaction
     at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:338)
     at $Proxy38.contains(Unknown Source)
     at com.gorkwobbler.shadowrun.karma.db.hibernate.DAO.isObjectPersistent(DAO.java:35)
    (reflection stuff omitted...)
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    (reflection stuff omitted...)
     at org.apache.wicket.proxy.LazyInitProxyFactory$JdkHandler.invoke(LazyInitProxyFactory.java:416)
     at org.apache.wicket.proxy.$Proxy36.isObjectPersistent(Unknown Source)
    

    我还从完整的堆栈跟踪中注意到正在调用OpenSessionInViewFilter,我不确定这是否相关。如果需要剩余的堆栈跟踪,请告诉我。

    这是我的应用程序上下文.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Reference: http://wicketinaction.com/2009/06/wicketspringhibernate-configuration/ -->
    <beans default-autowire="autodetect"
        xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
        <!-- bean definitions -->
        <bean id="wicketApplication" class="com.gorkwobbler.shadowrun.karma.view.wicket.core.WicketApplication" />
    
        <bean id="placeholderConfigurer"
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="ignoreUnresolvablePlaceholders" value="false" />
            <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
            <property name="ignoreResourceNotFound" value="false" />
            <property name="locations">
                <list>
                    <value>classpath*:/application.properties</value>
                </list>
            </property>
        </bean>
    
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName">
                <value>${jdbc.driver}</value>
            </property>
            <property name="url">
                <value>${jdbc.url}</value>
            </property>
            <property name="username">
                <value>${jdbc.username}</value>
            </property>
            <property name="password">
                <value>${jdbc.password}</value>
            </property>
        </bean>
    
        <tx:annotation-driven transaction-manager="txManager" />
    
        <!-- setup transaction manager  -->
        <bean id="txManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
    
        <!-- hibernate session factory -->
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
            <property name="configLocation">
                <value>classpath:/hibernate.cfg.xml</value>
            </property>
            <property name="dataSource" ref="dataSource" />
            <property name="hibernateProperties">
                <props>
                </props>
            </property>
            <property name="packagesToScan">
                <list>
                    <value>com.gorkwobbler.shadowrun.karma.domain</value>
                    <value>com.gorkwobbler.shadowrun.karma.domain.*</value>
                </list>
            </property>
        </bean>
    
        <bean id="dao"
            class="com.gorkwobbler.shadowrun.karma.db.hibernate.DAO">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
    
        <!-- Don't know what this is for, but it was in the sample config I started from --> 
        <!-- <context:component-scan base-package="com.gorkwobbler.shadowrun.karma" />  -->
    </beans>
    

    如何让我的DAO开始一个事务,在该方法结束时提交,或者在出错时回滚?我希望使用尽可能最小的/标准的配置;如果有选择的话,我更喜欢注释而不是XML。

    编辑:

    使用调试器,我确定存储在TransactionInterceptor会话持有者映射中的SessionImpl与调用时在DAO方法中检索到的SessionImpl不是同一个会话sessionFactory.getCurrentSession会话(). 有人能解释这是为什么吗?我做错什么了?魔法不起作用。=(

    编辑

    在启动期间,我还注意到控制台中的以下消息:

    WARN  - stractEhcacheRegionFactory - No TransactionManagerLookup found in Hibernate config, XA Caches will be participating in the two-phase commit!
    
    2 回复  |  直到 14 年前
        1
  •  3
  •   RMorrisey    14 年前

    事实证明,问题其实并不在我发布的配置信息中。对不起的!

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
    

        2
  •  2
  •   Sean Patrick Floyd    14 年前

    13.3.3 (Hibernate) Declarative transaction demarcation 尤其是最后一部分。如果您使用 @Transactional :

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
      <!-- SessionFactory, DataSource, etc. omitted -->
    
      <bean id="transactionManager"
                class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
      </bean>
    
      <tx:annotation-driven/>
    
      <bean id="myProductService" class="product.SimpleProductService">
        <property name="productDao" ref="myProductDao"/>
      </bean>
    
    </beans>
    

    回答您的意见:

    不,如果您通过Spring注入组件,Spring负责布线,hibernate不需要了解Spring的任何内容,这就是使用Spring(将各个层解耦)的全部意义。服务和dao不是每个人都使用的分离。重要的一点是,接口支持的公共方法被标记为transactional,因为所有标记为transactional的方法都将被执行事务处理的代理拦截,而其他方法则不会。

    你可能想读一下关于 Declarative Transaction Managmenet in Spring 理解流程(这适用于所有事务技术,而不仅仅是hibernate)。