2009-09-30 16 views
11

Esta pregunta es similar a una one anterior. Estoy tratando de @Autowire una sesión de Hibernate en una de mis pruebas Primavera-JUnit-transaccional pero yo estoy haciendo esta excepción:Forma correcta de autoautar una sesión de Hibernate en una prueba de la JUnit de la transacción de primavera

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

Aquí es mi clase 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]"); 
    } 
} 

Cada funciona bien si @Autowire un SessionFactory y obtener mi Session programación (en lugar de definirlo en el XML de primavera), así:

@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]"); 
    } 
} 

Puedo, sin embargo, tener en mis original ejemplo a trabajar si defino mi Session en mi XML primavera con <aop:scoped-proxy /> así:

<?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> 

Mi pregunta es: ¿Por qué se <aop:scoped-proxy /> necesario dado que sólo debe uno thread- contexto de transacción limitado en mi prueba de unidad? ¿Qué es la forma correcta de definir mi Hibernate Session frijol?

Respuesta

6

SessionFactoryUtils.getSession() es tan buena como cualquier otra forma de obtener la Sesión. Hace lo mismo que HibernateDaoSupport.getSession().

La razón por la que necesita el alcance del proxy es debido al tiempo. Sin el proxy de alcance parece que está inyectando la Sesión antes de que comience la prueba y, por lo tanto, antes de que comience la transacción y así se obtienen los errores.

Al agregar el proxy con alcance, proxyiza la sesión e inyecta eso para que no inyecte la sesión actual (antes de que comience la transacción) sino que solo la recupera y realiza llamadas una vez que se ejecuta la prueba, cuando en realidad necesita hacer una llamada en contra de esto.

4

Creo que la forma "correcta" es la inyección del SessionFactory, y la recuperación de la sesión mediante programación. La razón por la que usted está recibiendo la excepción se debe al comportamiento documentado de SessionFactoryUtils.getSession():

obtener una sesión de Hibernate para la dada SessionFactory. Es consciente de y devolverá cualquier Sesión existente existente vinculada a la secuencia actual, por ejemplo cuando se usa HibernateTransactionManager. Será crear una nueva sesión de lo contrario, si "allowCreate" es verdadero.

Como nada ha vinculado una sesión a la transacción actual, falla.

Mi sugerencia sería usar HibernateTemplate - defina una en su contexto y conéctela automáticamente a su prueba. HibernateTemplate tiene la mayoría de las mismas operaciones que una sesión de guerra, pero la sesión maneja el bit por usted. Solo debe poder hacer:

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

Gracias por la respuesta. Si configuro "allowCreate" como verdadero, Spring parece crear una segunda sesión de base de datos no transaccional, es decir, la anotación @Transactional no revierte mis cambios durante la prueba. El problema con el autoenvío de un HibernateTemplate es que tengo clases de nivel DAO que dependen de Session. Supongo que podría hacer que dependieran de HibernateTemplate y luego hacer un get (User.class ...) como sugirieron. Sin embargo, creo que estoy violando la Ley de Demeter, dado que la verdadera dependencia de la clase DAO es Session y NO HibernateTemplate. – 0sumgain

+0

¿Sus DAO se inyectan con una sesión o con una SessionFactory? Si está inyectando una sesión, probablemente quiera reconsiderar eso, probablemente no sea una buena idea. – skaffman

+0

Los DAO se inyectan con Session. ¿Puedes explicar por qué esa no es una buena idea? Gracias. – 0sumgain

Cuestiones relacionadas