-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Strange Transaktion behaviour in JUnit test
PostPosted: Tue Sep 22, 2009 9:42 am 
Newbie

Joined: Tue Sep 22, 2009 7:27 am
Posts: 4
Hello Board,

I am writing a JUnit Test in Spring and I don't understand the behaviour of the transaction.

In the @Before-method I create a SessionFactory and a HibernateTransactionManager which starts a transaction with transactionManager.getTransaction(new DefaultTransactionDefinition()). This transaction should be rolled back in the @After-method. The rollback is successfull as long as I only call sessionFactory.getCurrentSession().saveOrUpdate(). If I call sessionFactory.getCurrentSession().createQuery() after the persisting of the domain objects, the rollback doesn't work and the domain objects stay in the database.

Why does Hibernate behave like this? Does the sessionFactory.getCurrentSession().createQuery() start a separate transaction which gets automatically committed?

Here is the code of the testcase:

Code:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import de.kraemerit.msl.repository.HibernateArticleRepository;
import de.kraemerit.msl.repository.HibernateUnitRepository;


//Unit-Test only with Hibernate
public class HibernateArticleTest {
   private HibernateUnitRepository unitRepository;
   
   private HibernateArticleRepository articleRepository;

   private PlatformTransactionManager transactionManager;

   private TransactionStatus transactionStatus;
   
   @Before
   public void setUp() throws Exception {
      // setup the repository to test
      SessionFactory sessionFactory = createTestSessionFactory();
      unitRepository = new HibernateUnitRepository(sessionFactory);
      articleRepository = new HibernateArticleRepository(sessionFactory);
      // begin a transaction
      transactionManager = new HibernateTransactionManager(sessionFactory);
      transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
   }
   
   @Test
   public void testUnit() {
      Unit unit = new Unit();
      unit.setDescription("mm");
      unit.setFactor(1L);
      unitRepository.update(unit);
      
      Long id = unit.getId();
      
      unit = new Unit();
      unit.setDescription("m");
      unit.setFactor(1000L);
      unitRepository.update(unit);
      System.out.println(transactionStatus.toString());
      
      //getById() commits the transaction, rollback in tearDown doesn't work
      //therefore property "hibernate.hbm2ddl.auto -> create"
      unit = unitRepository.getById(id);

      assertTrue(unit.getDescription().equals("mm"));
   }
   
   
   @After
   public void tearDown() throws Exception {
      
//      transactionManager.commit(transactionStatus);
      // rollback the transaction to avoid corrupting other tests
      transactionManager.rollback(transactionStatus);
   }

   private SessionFactory createTestSessionFactory() throws Exception {
      // create a FactoryBean to help create a Hibernate SessionFactory
      LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();

       factoryBean.setDataSource(createDataSource());
   
      Resource[] mappingLocations = new ClassPathResource[] {
            new ClassPathResource("Unit.hbm.xml", HibernateUnitRepository.class),
            new ClassPathResource("Article.hbm.xml", HibernateUnitRepository.class)
            };
      factoryBean.setMappingLocations(mappingLocations);
      factoryBean.setHibernateProperties(createHibernateProperties());
      // initialize according to the Spring InitializingBean contract
      factoryBean.afterPropertiesSet();
      // get the created session factory
      return (SessionFactory) factoryBean.getObject();
   }

   private DataSource createDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        // use the MySql JDBC driver
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/xxx?autoReconnect=true");
        dataSource.setUsername("xxx");
        dataSource.setPassword("xxx");
        return dataSource;
    }

   private Properties createHibernateProperties() {
      Properties properties = new Properties();
      // turn on formatted SQL logging (very useful to verify Hibernate is
      // issuing proper SQL)
      properties.setProperty("hibernate.show_sql", "true");
      properties.setProperty("hibernate.format_sql", "true");
//      properties.setProperty("hibernate.hbm2ddl.auto", "create");
      properties.setProperty("hibernate.hbm2ddl.auto", "update");
      return properties;
   }
}   


Here is the code of the repository:
Code:
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import de.kraemerit.msl.domain.Unit;

public class HibernateUnitRepository implements UnitRepository {

   private SessionFactory sessionFactory;

   /**
    * Creates a new Hibernate category repository.
    * @param sessionFactory the Hibernate session factory
    */
   public HibernateUnitRepository(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
   }
   
   @Override
   public void update(Unit unit) {
      getCurrentSession().saveOrUpdate(unit);
      
   }

   @Override
   public Unit getById(Long id) {
      return (Unit) getCurrentSession().createQuery("Select u From Unit u where u.id = ?").setLong(0, id).uniqueResult();
   }
   
   @Override
   public Unit getByDescription(String description) {
      return (Unit) getCurrentSession().createQuery("Select u From Unit u where u.description = ?").setString(0, description).uniqueResult();
   }

   /**
    * Returns the transactional session
    * @return the transactional session
    */
   protected Session getCurrentSession() {
      return sessionFactory.getCurrentSession();
   }
}


Top
 Profile  
 
 Post subject: Re: Strange Transaktion behaviour in JUnit test
PostPosted: Wed Sep 23, 2009 5:05 am 
Newbie

Joined: Tue Sep 22, 2009 7:27 am
Posts: 4
Problem is solved. I used MySql and the default table is MyIsam which doesn't support transaction.

Turned to InnoDB -> works


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.