0

我在我的测试 persistence.xml 中定义了 2 个持久性单元,为每个连接数据库的集成测试创建 2 个不同的 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 中使用不同的 db 名称,这种情况仍然会发生。

我的persistence.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房产有关系?但是当我输入其他值时,数据不会插入数据库;只update工作。

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

4

1 回答 1

0

我发现了原因......我有一个基础集成测试,它重用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,是我的代码错误。

于 2021-09-16T09:20:39.810 回答