java - 在内存中使用 H2 数据库不会在单元测试中保留对象

标签 java unit-testing jpa h2 in-memory-database

我在用于单元测试的 persistence.xml 中遇到有关 JPA 的问题。 将对象持久化到内存中的数据库 H2 时发生错误:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running some.class.MyClass
################################################################################
                    BeforeClass Start  
################################################################################
                    EntityManager is being created..  
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.541 sec <<< FAILURE!

Results :

Tests in error: 
  some.class.MyClass: getSingleResult() did not retrieve any entities

我确信持久存在问题,而不是获取数据问题,因为 DEV 应用程序中的读取方法与真实数据库完美配合。

这是我的 persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="TestPU" transaction-type="RESOURCE_LOCAL">

        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>all entities</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="eclipselink.logging.level" value="SEVERE"/>
            <!-- ALL SEVERE -->
            <property name="eclipselink.logging.level.sql" value="SEVERE"/>
            <!-- ALL SEVERE -->
            <property name="eclipselink.logging.parameters" value="true"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS DEV"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <!-- model creation have to be done via javax.persistence, not hibernate/eclipselink - otherwise import doesn't works -->
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <property name="javax.persistence.schema-generation.create-source" value="metadata"/>
            <property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
        </properties>

    </persistence-unit>
</persistence>


</persistence-unit>

这是一段 Java 代码:

@BeforeClass
        public static void setUpClass() {
                myOut("BeforeClass Start");
                EM = Persistence.createEntityManagerFactory(PU).createEntityManager();
                myOut("EntityManager is being created..");
                EM.persist(new Account(PU, PU, PU));
                EM.persist(new Account(PU + "2", "dsaddsa", "dsadas"));
                EM.persist(new Account(PU + "3", "saddsd", "dsadasa"));
                EM.persist(new Account(PU + "4", "adsada", "hdsd"));

                final DaoLogged dao = new DaoLogged();
                dao.setEntityManager(EM);
                dao.getAccountByLogin(PU);
                myOut("BeforeClass Done.");
        }

单一结果方法:

public Account getAccountByLogin(String login) {
                return (Account) getEntityManager().createNamedQuery("Account.findByLogin").setParameter("login", login).getSingleResult();
}

我将不胜感激任何帮助! :) 问候!

[编辑]

我一直在寻找答案,实际上在今天早上这完全行不通,但是经过几个小时的编辑,在互联网上搜索我坚持了下来..

[编辑 2]

我把上面的方法改成了:

@BeforeClass
        public static void setUpClass() {
                myOut("BeforeClass Start");
                EM = Persistence.createEntityManagerFactory(PU).createEntityManager();
                myOut("EntityManager is being created..");

                **EM.getTransaction().begin();**

                EM.persist(new Account(PU, PU, PU));
                EM.persist(new Account(PU + "2", "dsaddsa", "dsadas"));
                EM.persist(new Account(PU + "3", "saddsd", "dsadasa"));
                EM.persist(new Account(PU + "4", "adsada", "hdsd"));
                **EM.getTransaction().commit();
                EM.flush();
                EM.getTransaction().begin();**
                final DaoLogged dao = new DaoLogged();
                dao.setEntityManager(EM);
                dao.getAccountByLogin(PU);
                myOut("BeforeClass Done.");
        }

仍然是错误,但有所不同:

javax.persistence.TransactionRequiredException: 

异常描述:当前没有活跃的事务

最佳答案

错误意味着查询没有返回任何结果。确保数据库设置正确。为此,为 EclipseLink 启用 DEBUG 日志级别。这应该会向您显示正在发送到数据库的 SQL。

您还需要一个事务管理器。如何设置和配置取决于您的应用程序的体系结构。事务管理器负责协调事务的所有不同参与者(数据库、EntityManager,有时还有其他各方,如 JMS)。

如果您使用 Spring,那么事务管理器会自动将事务与测试同步。

请注意,您应该尝试在每次测试之前启动事务并在每次测试之后回滚。这样,测试 #2 就不会因为测试 #1 在数据库中留下垃圾而失败。

关于java - 在内存中使用 H2 数据库不会在单元测试中保留对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28150593/

相关文章:

java - 可以安全地假设 @Transient 使 JPA 提供者始终保留带注释的字段吗?

java - JavaFX 中的寻路

java - 是否可以在 java 中制作类似 Comparator 但用于实现自定义 equals() 和 hashCode()

python - 我怎样才能模拟 sqlite3.Cursor

Java 测试扫描仪与假用户输入

java - 映射错误 : More than one row with the given identifier was found

java - Spring和Ehache : Cachemanger

java - 面板从 JFrame 中移除后如何处理 JPanel

ios - 未为测试目标生成核心数据类

java - spring data jpa的奇怪行为