Why are transactions not rolling back when using SpringJUnit4ClassRunner/MySQL/Spring/Hibernate

橙三吉。 提交于 2019-12-03 13:55:41

问题


I am doing unit testing and I expect that all data committed to the MySQL database will be rolled back... but this isn't the case. The data is being committed, even though my log was showing that the rollback was happening. I've been wrestling with this for a couple days so my setup has changed quite a bit, here's my current setup.

LoginDAOTest.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:web/WEB-INF/applicationContext-test.xml", "file:web/WEB-INF/dispatcher-servlet-test.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class UserServiceTest {

  private UserService userService;

  @Test
  public void should_return_true_when_user_is_logged_in ()
          throws Exception
  {
    String[] usernames = {"a","b","c","d"};

    for (String username : usernames)
    {
      userService.logUserIn(username);
      assertThat(userService.isUserLoggedIn(username), is(equalTo(true)));
    }
  }

ApplicationContext-Text.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
          <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
          <property name="url" value="jdbc:mysql://localhost:3306/******"/>
          <property name="username" value="*****"/>
          <property name="password" value="*****"/>
  </bean>

  <tx:annotation-driven transaction-manager="transactionManager"/>

  <bean id="userService" class="Service.UserService">
    <property name="userDAO" ref="userDAO"/>
  </bean>

  <bean id="userDAO" class="DAO.UserDAO">
    <property name="hibernateTemplate" ref="hibernateTemplate"/>
  </bean>

  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
      <list>
        <value>/himapping/User.hbm.xml</value>
        <value>/himapping/setup.hbm.xml</value>
        <value>/himapping/UserHistory.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
    </property>
  </bean>

  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
          p:sessionFactory-ref="sessionFactory"/>

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

</beans>

I have been reading about the issue, and I've already checked to ensure that the MySQL database tables are setup to use InnoDB. Also I have been able to successfully implement rolling back of transactions outside of my testing suite. So this must be some sort of incorrect setup on my part.

Any help would be greatly appreciated :)


回答1:


The problem turned out to be that the connection was auto-committing BEFORE the transaction could be rolled back. I had to change my dataSource bean to include a defaultAutoCommit property:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/test"/>
  <property name="username" value="root"/>
  <property name="password" value="Ecosim07"/>
  <property name="defaultAutoCommit" value="false" /> 
</bean>



回答2:


For me defaultAutoCommit and @Transactional didn't help. I had to change db type to InnoDB




回答3:


This must be used

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@Transactional

TransactionalTestExecutionListener contains isRollback() which rollbacks the transaction after the test method.




回答4:


I hope I am right and that this is a simple one. You are missing the @Transactional annotation on your test class. This means that the test method itself isn't run in a transaction and thus there is nothing to roll back. Hope this helps.




回答5:


Another way to fix your problem:

Instead of using:

<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>

, which creates a MyISAM table by default, hence not supporting transactions

Try using

<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>

, which creates InnoDB tables, and thus supports transactions.



来源:https://stackoverflow.com/questions/2827770/why-are-transactions-not-rolling-back-when-using-springjunit4classrunner-mysql-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!