简体   繁体   English

在Spring Transaction JUnit测试中自动装配Hibernate会话的正确方法

[英]Proper way to autowire a Hibernate Session in a Spring Transaction JUnit test

This question is similar to a previous one . 这个问题类似于前一个问题 I am trying to @Autowire a Hibernate Session in one of my Spring-JUnit-Transactional tests but I am getting this exception: 我试图在我的一个Spring-JUnit-Transactional测试中@Autowire一个Hibernate Session但是我得到了这个异常:

java.lang.IllegalStateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional ...

Here is my JUnit class: 这是我的JUnit类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager")
@Transactional
public class MyTest {
    @Qualifier("session")
    @Autowired
    private Session session;

    @Test
    public void testSomething() {
        session.get(User.class, "me@here.com");
    }
}

Every works fine if I @Autowire a SessionFactory and get my Session programmatically (instead of defining it in the Spring XML) like so: 如果我@Autowire一个SessionFactory并以编程方式获取我的Session (而不是在Spring XML中定义它),那么每个都可以正常工作:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager")
@Transactional
public class MyTest{    
    @Qualifier("sessionFactory")
    @Autowired
    private SessionFactory sessionFactory;

    @Test
    public void testSomething() {
    Session session = SessionFactoryUtils.getSession(sessionFactory, false);
        session.get(User.class, "me@here.com");
    }
}

I can, however, get my original example to work if I define my Session in my Spring XML with <aop:scoped-proxy /> like so: 但是,如果我使用<aop:scoped-proxy />在我的Spring XML中定义我的Session ,那么我可以得到我的原始示例:

<?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:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-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/aop 
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        ">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        ...
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation"><value>classpath:/hibernate.cfg.xml</value></property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="session" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession" scope="prototype">
        <constructor-arg ref="sessionFactory" />
        <constructor-arg value="false" />
        <!-- This is seems to be needed to get rid of the 'No Hibernate Session' error' -->
        <aop:scoped-proxy />
    </bean>
</beans>

My question is: Why is <aop:scoped-proxy /> needed given that there should only one thread-bounded transaction context in my unit test? 我的问题是:为什么需要<aop:scoped-proxy /> ,因为我的单元测试中只应该有一个线程限制的事务上下文? What is the proper way to define my Hibernate Session bean? 定义Hibernate Session bean的正确方法什么?

SessionFactoryUtils.getSession() is as good as any other way of getting the Session. SessionFactoryUtils.getSession()与获取Session的任何其他方式一样好。 It does the same thing HibernateDaoSupport.getSession() would do. HibernateDaoSupport.getSession()会做同样的事情。

The reason you need scoped-proxy is because of timing. 你需要scoped-proxy的原因是因为时间问题。 Without the scoped-proxy it seems that it is injecting the Session before the test begins and thus before the transaction begins and so you get the errors. 如果没有scoped-proxy,它似乎是在测试开始之前注入Session,因此在事务开始之前注入会话,因此你会得到错误。

By adding the scoped-proxy it proxies the Session and injects that so it does not inject the actual session upfront (before the transaction starts) but only fetches it and makes calls on it once the test is running, when it actually needs to make a call against it. 通过添加scoped-proxy,它代理Session并注入它,因此它不会预先注入实际会话(在事务开始之前),而是仅在测试运行时获取并调用它,当它实际需要创建一个时打电话给它。

I think the "proper" way is the injection of the SessionFactory , and programmatically fetching the Session from it. 我认为“正确”的方式是注入SessionFactory ,并以编程方式从中获取Session。 The reason that you're getting the exception is down to the documented behaviour of SessionFactoryUtils.getSession() : 您获得异常的原因归结为SessionFactoryUtils.getSession()的记录行为:

Get a Hibernate Session for the given SessionFactory. 获取给定SessionFactory的Hibernate会话。 Is aware of and will return any existing corresponding Session bound to the current thread, for example when using HibernateTransactionManager. 知道并将返回绑定到当前线程的任何现有对应Session,例如在使用HibernateTransactionManager时。 Will create a new Session otherwise, if "allowCreate" is true. 否则,如果“allowCreate”为true,则会创建一个新的Session。

Since nothing has bound a session to the current transaction, it fails. 由于没有任何内容将会话绑定到当前事务,因此失败。

My suggestion would be to use HibernateTemplate - define one in your context, and autowire that into your test. 我的建议是使用HibernateTemplate - 在你的上下文中定义一个,并将其自动装入你的测试中。 HibernateTemplate has most of the same operations as a war Session, but does the session handling bit for you. HibernateTemplate与war会话具有大部分相同的操作,但会为您处理会话处理。 You should just be able to do: 你应该能够做到:

hibernateTemplate.get(User.class, "me@here.com");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM