为什么我的(春季)HibernateTransactionManager无法在检票口工作? [英] Why doesn't my (spring)HibernateTransactionManager work in wicket?

查看:45
本文介绍了为什么我的(春季)HibernateTransactionManager无法在检票口工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将其简化为我认为相关的内容,我希望它足够且不至于使人感到压倒.请帮忙!

I tried to shorten this to what I think is relevant, I hope it's sufficient and not overwhelming. Please help!

我正在将一个小的 wicket + databinder + hibernate 网络应用程序转换为使用 wicket + spring + hibernate .我有一个DAO服务类,由Spring注入了一个休眠的SessionFactory.我可以使用会话工厂执行只读操作(默认情况下,自动提交处于启用状态).我想做的是使用HibernateTransactionManager和@Transactional批注进行事务操作.

I'm converting a small wicket+databinder+hibernate web application to use wicket+spring+hibernate. I have a DAO service class, with a hibernate SessionFactory injected by Spring. I am able to do read-only operations using the session factory (autocommit is on by default). What I want to do is use the HibernateTransactionManager and the @Transactional annotation to do a transactional operation.

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

I define a DAO service implementation, which uses an injected SessionFactory in a method marked @Transactional:

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()时,由于没有人调用session.beginTransaction(),我得到了一个休眠异常.

When I try to call isObjectPersistent(), I get a hibernate exception because no one has called session.beginTransaction():

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正在被调用,我不确定这是否有意义.让我知道您是否需要其余的堆栈跟踪.

I also notice from the full stack trace that the OpenSessionInViewFilter is being invoked, I'm not sure if that's relevant. Let me know if you need the rest of the stack trace.

如果我创建一个自定义的WebRequestCycle子类来开始事务,那么我可以克服这个问题.在我看来,这似乎破坏了@Transactional的目的,而我的实现也被证明是有问题的.

If I create a custom WebRequestCycle subclass, which begins a transaction, I can get past this. This seems to me to undermine the purpose of @Transactional, and my implementation of it also turned out to be problematic.

这是我的applicationContext.xml:

Here is my applicationContext.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.

How can I get my DAO to begin a transaction, commit at the end of that method, or rollback on error? I want to use the most minimal/standard configuration possible; I prefer annotations over XML if given the choice.

我修改了上面的applicationContext,以删除仍然无法运行的AOP配置内容.

I revised the applicationContext above to remove the AOP configuration stuff, which wasn't working, anyway.

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

Using the debugger, I determined that the SessionImpl stored in the TransactionInterceptor's session holder map is not the same session as the SessionImpl that is retrieved in the DAO method when I call sessionFactory.getCurrentSession(). Can anyone explain why this is? What am I doing wrong? The magic is not working. =(

修改

在启动过程中,我还在控制台中注意到以下消息:

I also notice the following message in my console during startup:

WARN  - stractEhcacheRegionFactory - No TransactionManagerLookup found in Hibernate config, XA Caches will be participating in the two-phase commit!

推荐答案

事实证明,问题实际上出在我发布的配置信息中.抱歉!

It turns out that the problem was not actually in the configuration information that I posted. Sorry!

我上面的配置链接到一个外部化的hibernate.cfg.xml,该文件声明了以下属性:

My above configuration links to an externalized hibernate.cfg.xml, which declared the following property:

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

我必须已经从某个示例休眠配置文件中的某处复制了此文件.此属性导致我的SessionFactory忽略spring提供的会话上下文,并在其位置使用线程本地上下文.删除此属性可解决问题(如果未指定,则默认情况下,Hibernate使用JTA上下文).

I must've copied this from some sample hibernate config file somewhere. This property caused my SessionFactory to ignore the session context provided by spring, and use a thread-local context in its place. Removing this property fixed the problem (hibernate uses the JTA context by default if none is specified).

这篇关于为什么我的(春季)HibernateTransactionManager无法在检票口工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆