为Hibernate测试配置HSQL Server

时间:2012-11-13 19:47:32

标签: java database hibernate unit-testing hsqldb

我刚刚开始使用Hibernate,并了解事情。

目前我正在尝试设置一个测试环境,我可以使用HSQL内存实例来测试我的项目。

我遇到的错误是:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: invalid schema name: TSG

以下是我项目的相关部分:

的persistence.xml

<?xml version="1.0" encoding="UTF-8"?>

             org.hibernate.ejb.HibernatePersistence         com.foo.api.models.tsg.AlgPpcAlgorithmOutputEntity                                                                                                                                        

<persistence-unit name="TestingPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.foo.api.models.tsg.AlgPpcAlgorithmOutputEntity
    </class>
    <properties>
        <property name="dialect" value="org.hibernate.dialect.HSQLDialect"/>
        <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
        <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:tsg"/>
        <property name="hbm2ddl.auto" value="create-drop"/>
        <property name="hibernate.connection.autocommit" value="true"/>
        <property name="hibernate.connection.username" value="sa"/>
        <property name="hibernate.connection.password" value=""/>
        <property name="hibernate.show_sql" value="true"/>
    </properties>
</persistence-unit>

正如您所看到的,我有一个peristence-unit用于生产(工作正常)和一个内存中的HSQL用于测试(我无法开始工作)。

示例Hibernate实体:

package com.foo.api.models.tsg;

import javax.persistence.*;
import java.math.BigDecimal;

@IdClass(AlgPpcAlgorithmOutputEntityPK.class)
@Table(name = "alg_ppc_algorithm_output", schema = "", catalog = "tsg")
@Entity
public class AlgPpcAlgorithmOutputEntity {
    private int parameterId;

    @Column(name = "parameter_id")
    @Id
    public int getParameterId() {
        return parameterId;
    }

    public void setParameterId(int parameterId) {
        this.parameterId = parameterId;
    }

    private String matchType;

    @Column(name = "matchType")
    @Basic
    public String getMatchType() {
        return matchType;
    }

    // for brevity I have removed the rest of the implementation
    // It was auto-generated by Hibernate and works fine in production.
}

最后,一个简单的TestCase类:

package tests.integration;


import com.foo.api.models.tsg.AlgPpcAlgorithmOutputEntity;
import com.foo.api.util.HibernateUtil;
import org.hsqldb.Server;
import org.hsqldb.persist.HsqlProperties;
import org.hsqldb.server.ServerConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tests.util.HSQLServerUtil;

import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;

import com.foo.api.KeywordManager;

import java.sql.Date;
import java.util.HashSet;

public class KeywordManagerTestCase {

    private static final Logger LOG =   LoggerFactory.getLogger(KeywordManagerTestCase.class);
    private EntityManagerFactory eMF;
    protected EntityManager eM;

    @Before
    public void setUp() throws Exception {

        HsqlProperties props = new HsqlProperties();
        props.setProperty("server.database.0", "mem:tsg");
        props.setProperty("server.dbname.0", "tsg");

        ServerConfiguration.translateDefaultDatabaseProperty(props);

        Server hsqlServer = new Server();
        hsqlServer.setRestartOnShutdown(false);
        hsqlServer.setNoSystemExit(true);
        hsqlServer.setProperties(props);
        hsqlServer.setTrace(true);

        LOG.info("Configured the HSQLDB server...");
        hsqlServer.start();
        LOG.info("HSQLDB server started on port " + hsqlServer.getPort() + "...");

        LOG.info("Loading hibernate...");
        if (eMF == null) {
            eMF = Persistence.createEntityManagerFactory("TestingPersistenceUnit");
        }

        eM = eMF.createEntityManager();
    }

    /**
     * shutdown the server.
     * @throws Exception in case of errors.
     */
    @After
    public void tearDown() throws Exception {
        eM.close();
        HSQLServerUtil.getInstance().stop();
    }

    /**
     * Demo test to see that the number of user records in the database corresponds the flat file inserts.
     */
    @Test
    public void testDemo1() {
        AlgPpcAlgorithmOutputEntity entity = new AlgPpcAlgorithmOutputEntity();
        entity.setParameterId(200);
        entity.setMatchType("aa");
        KeywordManager km;
        eM.persist(entity);

        HashSet<Integer> params = new HashSet<Integer>();
        params.add(200);
        km = new KeywordManager(eM, params, new Date[2]);

        HashSet<AlgPpcAlgorithmOutputEntity> res = km.pullKeywords(params);
        for (AlgPpcAlgorithmOutputEntity s : res) {
            System.out.println(s.getMatchType());
        }

    }


}

我确信我已经以一种奇怪的方式设置了一些东西,但正如我所说 - 这是我的第一次尝试。

这是我正在尝试做的事情:

  • 为persistence.xml中的HSQL数据库提供测试配置(以及所有hibernate类映射)
  • 让HSQL数据库启动进行单元测试,并使用我的项目模式创建内存数据库(如类元素下的persistence.xml中所述)。
  • 创建实体对象并在测试时将它们添加到测试数据库中,这样我就可以使用db进行集成测试。

我无法通过这个PersistenceException!

更新

好的,所以我意识到我不需要在我的测试用例的设置中设置一个显式的HSQL服务器,因为这正是我persistence-unit中的persistence.xml条目的用途。此外,我试图改变CATALOG,使其与我的映射类使用的目录相匹配。我的测试用例的设置现在看起来像:

private EntityManagerFactory eMF;
protected EntityManager eM;

@Before
public void setUp() throws Exception {
    LOG.info("Loading hibernate...");
    if (eMF == null) {
        eMF = Persistence.createEntityManagerFactory("TestingPersistenceUnit");
    }

    eM = eMF.createEntityManager();

    EntityTransaction eT = null;
    eT = eM.getTransaction();
    eT.begin();
    Query q = eM.createNativeQuery("ALTER CATALOG PUBLIC RENAME TO TSG");
    q.executeUpdate();
    eT.commit();

    // And also it seems I need to create the schema
    eT = eM.getTransaction();
    eT.begin();
    q = eM.createNativeQuery("CREATE SCHEMA TSG AUTHORIZATION DBA");
    q.executeUpdate();
    eT.commit();
}

但是,我现在最终得到一个新错误,具体来说:

javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: ALG_PPC_ALGORITHM_OUTPUT

所以我到了某处,但似乎没有创建表格。我想知道我的persistence.xml是否存在问题?

4 个答案:

答案 0 :(得分:3)

据我所知(并且我不是HSQL专家),您在连接URL中指定的TSG是与目录不同的数据库名称。见http://hsqldb.org/doc/2.0/guide/databaseobjects-chapt.html#dbc_schemas_schema_objects

  

在HyperSQL中,每个数据库只有一个目录。目录的名称是PUBLIC。您可以使用ALTER CATALOG RENAME TO语句重命名目录。所有模式都属于此目录。目录名称与数据库的文件名无关。

正如我读到的那样,当HSQL创建数据库时,它会在该数据库中创建一个名为PUBLIC的目录,并在该目录中创建一个名为PUBLIC的模式。每个HSQL数据库只能有一个目录。该单一目录中可以有多个模式。

您获得的错误实际上来自于在映射中指定catalog = "tsg"的尝试。该目录不存在。由于HSQL数据库只能包含一个目录,因此您必须将PUBLIC目录重命名为TSG(或更改映射)。

答案 1 :(得分:2)

您正在URL中指定服务器名称,但尝试使用导致此问题的内存数据库。

尝试将DB URL用作:

           jdbc:hsqldb:mem:tsg

  <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:tsg"/>

还可以使用ALTER CATALOG RENAME TO tsg更改默认目录名称(PUBLIC)。

编辑:要自动创建架构,请在persistence.xml中更新以下内容(hibernate.hbm2ddl.auto代替hbm2ddl.auto)

    <property name="hibernate.hbm2ddl.auto" value="create-drop"/>

答案 2 :(得分:1)

您可以通过将orm.xml文件放入src / test / resources / META-INF(如果使用maven布局)来覆盖单元测试的实体映射。在此,您可以覆盖JPA注释映射。根据您的需要,您只需覆盖表位置,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

  <entity class="com.foo.api.models.tsg.AlgPpcAlgorithmOutputEntity">
    <table name="alg_ppc_algorithm_output"/>
  </entity>

</entity-mappings>

这会将您的表放入hsqldb数据库的默认公共目录中,因此您不必更改hsqldb方案。当您的单元测试使用包含同名表的多个目录时,它甚至可以工作,因为您只需在表名属性中给出不同的名称。

答案 3 :(得分:0)

设置中存在明显错误。连接URL必须指向服务器:

<property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost/tsg"/>