views:

11664

answers:

4

Hi

I'm trying to access the current hibernate session in a test case, and getting the following error:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63) at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:574)

I've clearly missed some sort of setup, but not sure what.

Any help would be greatly appreciated. This is my first crack at Hibernate / Spring etc, and the learning curve is certainly steep!

Regards

Marty

Code follows:

The offending class:

public class DbUnitUtil extends BaseDALTest {
    @Test
    public void exportDtd() throws Exception
    {

     Session session = sessionFactory.getCurrentSession();

     session.beginTransaction();
        Connection hsqldbConnection = session.connection(); 

        IDatabaseConnection connection = new DatabaseConnection(hsqldbConnection);

        // write DTD file
        FlatDtdDataSet.write(connection.createDataSet(), new FileOutputStream("test.dtd"));
    }
}

Base class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class BaseDALTest extends AbstractJUnit4SpringContextTests {
    public BaseDALTest()
    {
     super();
    }
     @Resource
     protected SessionFactory sessionFactory;
}

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName">
      <value>org.hsqldb.jdbcDriver</value>
     </property>
     <property name="url">
      <value>jdbc:hsqldb:mem:sample</value>
     </property>
     <property name="username">
      <value>sa</value>
     </property>
     <property name="password">
      <value></value>
     </property>
    </bean>

    <bean id="sessionFactory" class="com.foo.spring.AutoAnnotationSessionFactoryBean">
     <property name="dataSource" ref="dataSource" />
     <property name="entityPackages">
      <list>
       <value>com.sample.model</value>
      </list>
     </property>
     <property name="schemaUpdate">
      <value>true</value>
     </property>
     <property name="hibernateProperties">
      <props>
       <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect
       </prop>
       <prop key="hibernate.show_sql">true</prop>
      </props>
     </property>
    </bean>
</beans>
+2  A: 

Duh.

Session session = sessionFactory.openSession();

Oops.

Marty Pitt
actually, this is totally wrong. You want to call getCurrentSession() otherwise you will be responsible for closing it and your transactions won't work with the annotation driven model.
Justin
+3  A: 

Wrong, that will just fill your code with session management code.

First, add a transaction management bean in your context:

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

The second thing, extend AbstractTransactionalJUnit4SpringContextTests

    public class BaseDALTest 
           extends AbstractTransactionalJUnit4SpringContextTests{

Third thing, annotate you test class with

    @TransactionConfiguration
    @Transactional

If your transaction demarcation is correct(surrounding your dao or service) you should be done.

It's not nice to sprinkle session and transaction handling code all around your code (even inside your tests).

Bogdan
+1  A: 

With the above Spring configuration, it should be sufficient to code

Session session = sessionFactory.getCurrentSession();

in your method and class to test. Session management is done by the Hibernate / Spring /JUnit test configuration, as later is done in the Hibernate / Spring configuration in the real application.

This is how it worked for my tests. In the final web application there will automatically be a Hibernate session associated with the current web request and therefore in testing there should be no sessionFactory.openSession() call.

+1  A: 

Please refer to the Spring documentation. There is a whole chapter on testing, and a section on transaction management:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html#testing-tx

I've had success extending AbstractTransactionalJUnit4SpringContextTests, but there's a workaround:

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        // DAO has access to the session through sessionFactory.getCurrentSession()
        myDao.findSomething(id);
    }
});
Nicolas Marchildon