2012-01-03 104 views
4

我在我的應用程序中創建了Spring集成測試。 問題是,一個測試不能正確回滾,在數據庫中留下一些東西並導致後續測試失敗。春季測試 - 回滾問題

我注意到,如果持久化實體是簡單的實體,那麼測試的效果很好。 當實體是繼承層次結構的一部分並且繼承類型的類型爲InheritanceType.JOINED時,測試失敗。 當我將其更改爲InheritanceType.SINGLE_TABLE時,它不會失敗。

下面是代碼: 測試類:

@RunWith(SpringJUnit4ClassRunner.class) 
@Transactional 
@ContextConfiguration(locations = {"classpath:beans/repository-beans.xml"}) 
public class OnlyParentRollbackProblemSpringTest { 
@PersistenceContext 
private EntityManager entityManager; 

@Test 
//PASSES 
public void isDBEmptyTest_1() throws Exception { 
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi"); 
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue(); 
    assertThat(elementsCount).isEqualTo(0); 
} 

@Test 
//PASSES 
public void testThatInfluencesOtherTests() { 
    ParentEntity queueItem = new ParentEntity(); 
    entityManager.persist(queueItem); 
    ParentEntity queueItem1 = new ParentEntity(); 
    entityManager.persist(queueItem1); 
    // given 
    flush(); 
    // when 
    Query deleteQuery = entityManager.createQuery("delete from " + ParentEntity.class.getSimpleName()); 
    deleteQuery.executeUpdate(); 
    flush(); 
    // then 
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi"); 
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue(); 
    assertThat(elementsCount).isEqualTo(0); 
} 

@Test 
//FAILS 
public void isDBEmptyTest_2() throws Exception { 
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi"); 
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue(); 
    assertThat(elementsCount).isEqualTo(0); 
} 

private void flush() { 
    entityManager.flush(); 
    entityManager.clear(); 
} 
} 

Spring配置:

<?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:context="http://www.springframework.org/schema/context" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 


<context:component-scan base-package="no.mintra.offlinetrainingportal.infrastructure.persistence" /> 

<bean 
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

<bean 
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

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

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    <property name="dataSource" ref="H2DataSource" /> 
</bean> 


<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" /> 
    <property name="dataSource" ref="H2DataSource" /> 
    <property name="jpaVendorAdapter" ref="H2JpaVendorAdaptor" /> 
    <property name="jpaPropertyMap"> 
     <map> 
      <entry key="hibernate.hbm2ddl.auto" value="create-drop" /> 
     </map> 
    </property> 
</bean> 

<bean id="H2DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="org.h2.Driver"/> 
    <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MYSQL;LOCK_MODE=3"/> 
</bean> 

<bean id="H2JpaVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
    <property name="showSql" value="true" /> 
    <property name="generateDdl" value="true" /> 
    <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" /> 
</bean> 

實體:

@javax.persistence.Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public class ParentEntity { 
@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Integer id; 

public ParentEntity() { 
} 

public Integer getId() { 
    return id; 
} 

public void setId(Integer id) { 
    this.id = id; 
} 
} 

@Entity 
public class SecondChildEntity extends ParentEntity { 
@Column(unique = true) 
@NotNull 
private Integer userId; 

public SecondChildEntity(Integer userId) { 
    this.userId = userId; 
} 

public Integer getUserId() { 
    return userId; 
} 
} 

而且pom.xml文件:

<project xmlns="http://maven.apache.org/POM/4.0.0"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
<modelVersion>4.0.0</modelVersion> 

<groupId>test</groupId> 
<artifactId>test</artifactId> 
<version>0.0.1-SNAPSHOT</version> 
<packaging>jar</packaging> 

<name>test</name> 
<url>http://maven.apache.org</url> 

<properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <junit.version>4.8.1</junit.version> 
    <org.springframework.version>3.1.0.RELEASE</org.springframework.version> 
    <log4j.version>1.2.15</log4j.version> 
    <org.slf4j.version>1.5.8</org.slf4j.version> 
    <hibernate-core.version>3.6.8.Final</hibernate-core.version> 
    <hibernate-validator.version>4.1.0.Final</hibernate-validator.version> 
    <commons-dbcp.version>1.2.2</commons-dbcp.version> 
    <h2database.version>1.3.163</h2database.version> 
    <commons-collections.version>3.2.1</commons-collections.version> 
    <javax.servlet.version>2.5</javax.servlet.version> 
    <javax.validation.version>1.0.0.GA</javax.validation.version> 
    <fest.version>1.2</fest.version> 
</properties> 

<build> 
    <plugins> 
     <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-compiler-plugin</artifactId> 
      <configuration> 
       <encoding>UTF-8</encoding> 
       <source>1.6</source> 
       <target>1.6</target> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 

<dependencies> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>${junit.version}</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>com.h2database</groupId> 
     <artifactId>h2</artifactId> 
     <version>${h2database.version}</version> 
     <scope>test</scope> 
    </dependency> 

    <dependency> 
     <groupId>org.easytesting</groupId> 
     <artifactId>fest-assert</artifactId> 
     <version>${fest.version}</version> 
     <scope>test</scope> 
    </dependency> 

    <dependency> 
     <groupId>log4j</groupId> 
     <artifactId>log4j</artifactId> 
     <version>${log4j.version}</version> 
     <exclusions> 
      <exclusion> 
       <groupId>com.sun.jmx</groupId> 
       <artifactId>jmxri</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 

    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <version>${org.slf4j.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-log4j12</artifactId> 
     <version>${org.slf4j.version}</version> 
    </dependency> 


    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-validator</artifactId> 
     <version>${hibernate-validator.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-core</artifactId> 
     <version>${org.springframework.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context</artifactId> 
     <version>${org.springframework.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-tx</artifactId> 
     <version>${org.springframework.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-test</artifactId> 
     <version>${org.springframework.version}</version> 
     <scope>test</scope> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-orm</artifactId> 
     <version>${org.springframework.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-entitymanager</artifactId> 
     <exclusions> 
      <exclusion> 
       <groupId>org.hibernate</groupId> 
       <artifactId>ejb3-persistence</artifactId> 
      </exclusion> 
     </exclusions> 
     <version>${hibernate-core.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-core</artifactId> 
     <version>${hibernate-core.version}</version> 
    </dependency> 

</dependencies> 

回答

3

這個問題是特定於H2 DBMS。

H2Dialect包含以下警告:

if (!(majorVersion > 1 || minorVersion > 2 || buildId >= 139)) { 
    log.warn(
     "The {} version of H2 implements temporary table creation such that it commits " + 
     "current transaction; multi-table, bulk hql/jpaql will not work properly", 
     (majorVersion + "." + minorVersion + "." + buildId) 
    ); 
} 

因爲執行批量delete對實體JOINED繼承涉及臨時表(見生成的SQL)的創建,使交易的第一部分被提交你面對這個問題。

作爲解決方法,您可以使用原生SQL查詢而不是批量HQL delete查詢。或者只是使用另一個內存數據庫,如HSQLDB。