2009-09-30 5 views
11

Cette question est semblable à une précédente one. Je suis en train de @Autowire une session Hibernate dans l'un de mes tests printemps-JUnit-transactionnelles mais je reçois cette exception:Façon correcte d'autowire une session Hibernate dans un test JUnit de transaction de printemps

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

Voici ma classe 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]"); 
    } 
} 

Chaque fonctionne très bien si je @Autowire un SessionFactory et obtenir mon Session programme (au lieu de le définir dans le code XML de printemps) comme ceci:

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

je peux, cependant, obtenir mon exemple original de travailler si je définis mon Session dans mon XML Spring avec <aop:scoped-proxy /> comme ceci:

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

Ma question est: Pourquoi est-<aop:scoped-proxy /> nécessaire étant donné qu'il ne devrait un thread- contexte de transaction limitée dans mon test unitaire? Qu'est-ce que est la bonne façon de définir mon haricot Hibernate Session? SessionFactoryUtils.getSession() est aussi bon que n'importe quel autre moyen d'obtenir la session

Répondre

6

Il fait la même chose que HibernateDaoSupport.getSession() ferait.

La raison pour laquelle vous avez besoin de proxy-scoped est due au timing. Sans le proxy-scoped, il semble qu'il injecte la session avant que le test ne commence et donc avant que la transaction ne commence et ainsi vous obtenez les erreurs. En ajoutant le proxy scoped, il charge la session et injecte celle-ci de sorte qu'elle n'injecte pas la session actuelle (avant le début de la transaction), mais seulement la récupère et l'appelle une fois le test en cours. doit faire un appel contre elle.

4

Je pense que la "bonne" façon est l'injection de la SessionFactory, et la récupération par programme de la session. La raison pour laquelle vous obtenez l'exception est en baisse au comportement documenté de SessionFactoryUtils.getSession():

une Session Hibernate pour la donnée SessionFactory. Est au courant de et retournera session existante liée au fil actuel, par exemple lors de l'utilisation de HibernateTransactionManager. Will créer une nouvelle session sinon, si "allowCreate" est vrai.

Étant donné que rien n'a lié une session à la transaction en cours, elle échoue.

Ma suggestion serait d'utiliser HibernateTemplate - définissez-en un dans votre contexte, et autowire cela dans votre test. HibernateTemplate a la plupart des mêmes opérations qu'une session de guerre, mais gère le bit de gestion de session pour vous. Vous devriez juste être capable de faire:

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

Merci pour la réponse. Si j'ai défini "allowCreate" sur true, Spring apparaît pour créer une deuxième session de base de données non transactionnelle, c'est-à-dire que l'annotation @Transactional n'annule pas mes modifications pendant le test. Le problème avec autowiring un HibernateTemplate est que j'ai des classes au niveau DAO qui dépendent de Session. Je suppose que je pourrais les faire dépendre de HibernateTemplate et ensuite faire un get (User.class ...) comme vous l'avez suggéré. Cependant, j'ai l'impression de violer la loi de Demeter, étant donné que la véritable dépendance de la classe DAO est Session et NOT HibernateTemplate. – 0sumgain

+0

Vos DAO sont-ils injectés avec une session ou avec une SessionFactory? Si vous injectez une session, vous voudrez probablement la repenser, ce n'est probablement pas une bonne idée. – skaffman

+0

DAO sont injectés avec Session. Pouvez-vous expliquer pourquoi ce n'est pas une bonne idée? Merci. – 0sumgain

Questions connexes