我正在尝试使用Spring测试实体EJB3。
EJB本身不使用Spring,并且我想使生产JPA配置的重复保持最少(例如,不重复persistence.xml)。
我的单元测试似乎可以正常工作,但是即使我的单元测试应该是事务性的,数据仍会在各种测试方法之间持久存在……
这是我的实体:
package sample; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Ejb3Entity { public Ejb3Entity(String data) { super(); this.data = data; } private Long id; private String data; @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
我的单元测试:
package sample; import static org.junit.Assert.*; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/appContext.xml"}) @Transactional public class Ejb3EntityTest { @PersistenceContext EntityManager em; @Before public void setUp() throws Exception { Ejb3Entity one = new Ejb3Entity("Test data"); em.persist(one); } @Test public void test1() throws Exception { Long count = (Long) em.createQuery("select count(*) from Ejb3Entity").getSingleResult(); assertEquals(Long.valueOf(1l), count); } @Test public void test2() throws Exception { Long count = (Long) em.createQuery("select count(*) from Ejb3Entity").getSingleResult(); assertEquals(Long.valueOf(1l), count); } }
和我的appContext.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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm" /> <property name="allowCustomIsolationLevels" value="true" /> </bean> <bean id="dataSource" class="org.enhydra.jdbc.standard.StandardXADataSource"> <property name="driverName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:mem:unittest;DB_CLOSE_DELAY=-1" /> <property name="user" value="" /> <property name="password" value="" /> <property name="transactionManager" ref="jotm" /> </bean> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitPostProcessors"> <bean class="sample.JtaDataSourcePersistenceUnitPostProcessor"> <property name="jtaDataSource" ref="dataSource" /> </bean> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="false" /> <property name="generateDdl" value="true" /> <property name="database" value="H2" /> <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" /> </bean> </property> <property name="jpaPropertyMap"> <map> <entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JOTMTransactionManagerLookup" /> <entry key="hibernate.transaction.auto_close_session" value="false" /> <entry key="hibernate.current_session_context_class" value="jta" /> </map> </property> </bean> </beans>
当我运行测试时,test2失败,因为它找到了两个我只希望有一个实体的实体(因为第一个实体应该已经回滚了……)
我尝试了很多不同的配置,而这似乎是我能得到的最全面的配置。你做 ?
我设法使用Bitronix而不是JOTM 使其工作。Bitronix提供了一个LrcXADataSource,它允许非XA数据库参与JTA事务。
我认为问题在于H2不符合XA且enhydra StandardXADataSource并非如此神奇(我也结束了使用HSQLDB的工作,但这与问题无关)。
StandardXADataSource
这是我的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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- Bitronix Transaction Manager embedded configuration --> <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices"> <property name="serverId" value="spring-btm" /> <property name="journal" value="null" /> </bean> <!-- create BTM transaction manager --> <bean id="BitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource" destroy-method="shutdown" /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="BitronixTransactionManager" /> <property name="userTransaction" ref="BitronixTransactionManager" /> <property name="allowCustomIsolationLevels" value="true" /> </bean> <!-- DataSource definition --> <bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close"> <property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource" /> <property name="uniqueName" value="unittestdb" /> <property name="minPoolSize" value="1" /> <property name="maxPoolSize" value="3" /> <property name="allowLocalTransactions" value="true" /> <property name="driverProperties"> <props> <prop key="driverClassName">org.hsqldb.jdbcDriver</prop> <prop key="url">jdbc:hsqldb:mem:unittestdb</prop> <prop key="user">sa</prop> <prop key="password"></prop> </props> </property> </bean> <!-- Entity Manager Factory --> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> <property name="generateDdl" value="true" /> <property name="database" value="HSQL" /> </bean> </property> <property name="jpaPropertyMap"> <map> <entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" /> <entry key="hibernate.transaction.auto_close_session" value="false" /> <entry key="hibernate.current_session_context_class" value="jta" /> </map> </property> </bean>