Jave EE 中的休眠 + H2:定义多个持久性单元导致测试失败并出现除第一个错误之外"Not an entity"错误



我在测试persistence.xml中定义了两个持久性单元,为每个集成测试连接数据库创建两个不同的H2内存数据库。

单独运行时,测试很好,可以通过,但当我运行所有测试时,只有第一个通过,第二个失败,其中:

java.lang.IllegalArgumentException: Not an entity: class com.data.item.ItemHistory
at org.hibernate.ejb.metamodel.MetamodelImpl.entity(MetamodelImpl.java:184)
at org.hibernate.ejb.criteria.QueryStructure.from(QueryStructure.java:138)
at org.hibernate.ejb.criteria.CriteriaQueryImpl.from(CriteriaQueryImpl.java:179)

显然,我在类上有@Entity注释。

而且,即使我告诉H2在最后一个连接结束时销毁(DB_CLOSE_ON_EXIT=TRUE;DB_CLOSE_DELAY=0;),并在每个PU中使用不同的数据库名称,这种情况仍然会发生。

我的持久性.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!-- For H2 database integration tests. -->
<!-- For each int test, define unique name PU in this file and include SQL files in different paths. -->
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="ItemHistoryPersistenceServiceBeanIntTest" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- this is the correct provider, differ from src/main -->
<class>com.data.company.Company</class>
<class>com.data.item.ItemHistory</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test1;DB_CLOSE_ON_EXIT=TRUE;DB_CLOSE_DELAY=0;MODE=Oracle;INIT=
RUNSCRIPT FROM 'src/test/resources/db/ddl/init.sql';
RUNSCRIPT FROM 'src/test/resources/db/ddl/company.sql';
RUNSCRIPT FROM 'src/test/resources/db/ddl/item-history.sql';
RUNSCRIPT FROM 'src/test/resources/db/dml/company-data.sql';
RUNSCRIPT FROM 'src/test/resources/db/dml/item-history-data.sql';"
/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- only "update" allows DML -->
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.default_schema" value="APP"/>
</properties>
</persistence-unit>
<persistence-unit name="CompanyPersistenceServiceBeanIntTest" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.data.company.Company</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test2;DB_CLOSE_ON_EXIT=TRUE;DB_CLOSE_DELAY=0;MODE=Oracle;INIT=
RUNSCRIPT FROM 'src/test/resources/db/ddl/init.sql';
RUNSCRIPT FROM 'src/test/resources/db/ddl/company.sql';
RUNSCRIPT FROM 'src/test/resources/db/dml/company-data.sql';"
/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.default_schema" value="APP"/>
</properties>
</persistence-unit>
</persistence>

这使我无法使用H2;为什么我不能同时使用多个内存中的数据库?

我认为这与ddl-auto属性有关?但当我放入其他值时,数据不会插入数据库;只有CCD_ 4起作用。

我可以拥有多个内存中的H2数据库吗?如果没有,其他哪些模式同时适用于多个数据库?尝试了tcp,但没有成功。我试图以嵌入式模式(在物理文件中)定义数据库,但无法工作。我在每个PU中将SQL和xml中的模式更改为不同的名称,但无法工作。

我发现了原因。。。我有一个基本集成测试,它重用EntityManagerFactory(当有新工厂时停止创建),所以重用导致了问题。

public abstract class H2DBIntBaseTest<T> {
protected EntityManager realEntityManager;
protected static EntityManagerFactory factory;
protected T serviceBean;
public abstract T initServiceBean();

@Before
public void setupEntityManager() {
// we don't care double creation/sychronization here, as they are the same
// Make sure the PU name in persistence.xml matches the test class name
if (factory == null) { // <----- here is the problem!
factory = Persistence.createEntityManagerFactory(getClass().getSimpleName());
}
realEntityManager = factory.createEntityManager();
EntityManager spy = spy(realEntityManager);
serviceBean = initServiceBean();
try {
// inject the real entity manager, instead of using mocks
Field entityManagerField = serviceBean.getClass().getDeclaredField("entityManager");
entityManagerField.setAccessible(true);
entityManagerField.set(serviceBean, spy);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new AssertionError("should not reach here");
}
}
@After
public void teardown() {
realEntityManager.close();
}
}

我去掉了检查null的行,它起作用了。

这不是H2,不是Hibernate,这是我的代码错误。

最新更新