Reputation: 2027
I develop application using Spring, Hibernate and MySQL. I created DAO for one of my tables. Now, I would like to test DAO's methods (save, find etc.). The problem is that these methods affect on database data, so I would like to rollback all changes after particular method execution. I tried do this by setting defaultRollback=true
in @TransactionConfiguration
but it doesn't work. Below I paste most important fragments of code. Does anyone know how to force rollback after each method?
My table in MySQL is using InnoDB engine.
In fact, after test execution console contains this information:
INFO: Rolled back transaction after test execution for test context ...
but changes in database are commited.
UsersDAOTest
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
@Transactional
public class UsersDAOTest {
@Autowired
UsersHibernateDAO usersDAO;
@Test
public void test1() {
List<Users> results = usersDAO.findAll();
Assert.assertEquals(0, results.size());
}
@Test
public void test2() {
Users user = new Users("mchrobok", "12345678901234567890123456789012");
usersDAO.saveOrUpdate(user);
List<Users> results = usersDAO.findAll();
Assert.assertEquals(1, results.size());
}
}
Hibernate (hibernate.cfg.xml)
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">create-drop</property>
<mapping class="pl.fp.microblog.domain.Users"/>
</session-factory>
</hibernate-configuration>
Spring configuration (applicationContext.xml)
<beans>
<context:component-scan base-package="pl.fp.microblog" />
<tx:annotation-driven />
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<beans:property name="url" value="jdbc:mysql://localhost:3306/Microblog"/>
<beans:property name="username" value="root"/>
<beans:property name="password" value="root"/>
</beans:bean>
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation">
<beans:value>
hibernate.cfg.xml
</beans:value>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
<beans:bean name="usersDAO" class="pl.fp.microblog.dao.UsersHibernateDAO">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
</beans:beans>
EDIT
UsersDAO (it's generic, but it doesn't matter)
public class GenericHibernateDAO<T> implements GenericDAO<T> {
private SessionFactory sessionFactory;
private Class<?> persistClass;
public GenericHibernateDAO() {
ParameterizedType type = ((ParameterizedType)getClass().getGenericSuperclass());
persistClass = ((Class<?>) type.getActualTypeArguments()[0]);
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public List<T> findAll() {
Criteria criteria = sessionFactory.openSession().createCriteria(persistClass);
return criteria.list();
}
@Override
public void saveOrUpdate(T entity) {
sessionFactory.openSession().saveOrUpdate(entity);
}
}
Upvotes: 1
Views: 5062
Reputation: 17774
You are opening a new session in your hibernate code, you should use getCurrentSession() instead.
The problem in your code is that your DAO class tries to manage transactions on its own. In modern Spring applications the transaction management should be performed in the service layer.
So it means that typically your service methods should be annotated with @Transactional
.
Upvotes: 4