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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1500775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:32:12  来源:igfitidea点击:

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

javahibernatespringtransactionsjunit

提问by 0sumgain

This question is similar to a previous one. I am trying to @Autowirea Hibernate Session in one of my Spring-JUnit-Transactional tests but I am getting this exception:

这个问题与上一个类似。我正在尝试@Autowire在我的 Spring-JUnit-Transactional 测试之一中进行休眠会话,但出现此异常:

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

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, "[email protected]");
    }
}

Every works fine if I @Autowirea SessionFactoryand get my Sessionprogrammatically (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, "[email protected]");
    }
}

I can, however, get my original example to work if I define my Sessionin my Spring XML with <aop:scoped-proxy />like so:

但是,如果我Session在 Spring XML 中<aop:scoped-proxy />像这样定义我的话,我可以让我的原始示例工作:

<?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? What isthe proper way to define my Hibernate Sessionbean?

我的问题是:<aop:scoped-proxy />鉴于我的单元测试中应该只有一个线程有界事务上下文,为什么需要?定义我的bean的正确方法什么Hibernate Session

采纳答案by Michael Wiles

SessionFactoryUtils.getSession() is as good as any other way of getting the Session. It does the same thing HibernateDaoSupport.getSession() would do.

SessionFactoryUtils.getSession() 与获取 Session 的任何其他方式一样好。它做 HibernateDaoSupport.getSession() 会做的同样的事情。

The reason you need scoped-proxy is because of timing. 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.

您需要作用域代理的原因是时间问题。如果没有作用域代理,它似乎在测试开始之前注入会话,因此在事务开始之前,因此您会收到错误。

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.

通过添加作用域代理,它代理 Session 并注入它,因此它不会预先注入实际的会话(在事务开始之前),而是只在测试运行时获取它并在它实际需要进行调用时进行调用呼吁反对它。

回答by skaffman

I think the "proper" way is the injection of the SessionFactory, and programmatically fetching the Session from it. The reason that you're getting the exception is down to the documented behaviour of SessionFactoryUtils.getSession():

我认为“正确”的方法是注入SessionFactory,并以编程方式从中获取会话。您收到异常的原因归结为以下记录的行为SessionFactoryUtils.getSession()

Get a Hibernate Session for the given SessionFactory. Is aware of and will return any existing corresponding Session bound to the current thread, for example when using HibernateTransactionManager. Will create a new Session otherwise, if "allowCreate" is true.

获取给定 SessionFactory 的 Hibernate Session。知道并将返回绑定到当前线程的任何现有的相应 Session,例如在使用 HibernateTransactionManager 时。否则将创建一个新会话,如果“allowCreate”为真。

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. HibernateTemplatehas most of the same operations as a war Session, but does the session handling bit for you. You should just be able to do:

我的建议是使用HibernateTemplate- 在您的上下文中定义一个,并将其自动装配到您的测试中。HibernateTemplate具有与战争会话相同的大部分操作,但会为您处理会话。你应该能够做到:

hibernateTemplate.get(User.class, "[email protected]");