2012-11-13 36 views
3

我刚刚开始使用Hibernate,并开始着手解决问题。配置HSQL服务器进行休眠测试

目前我正在尝试设置一个测试环境,我可以使用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.AlgPpcAlgorithm OutputEntity

<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()); 
     } 

    } 


} 

我敢肯定,我已经设置的东西了在陌生的路上,但就像我说的 - 这是我的第一个刺。

这里是我想要做的事:

  • 有测试配置(与所有的休眠类映射一起)为HSQL DB目前在persistence.xml中
  • 有HSQL DB开始用于单元测试以及使用我的项目模式创建内存数据库(如persistence.xml中类元素下所述)。
  • 创建实体对象并在测试时将它们添加到测试数据库中,以便我可以将该数据库用于我的集成测试。

我只是无法超越这个PersistenceException!

UPDATE

好了,我意识到,我并不需要安装在我的测试情况下,设置一个明确的HSQL服务器,因为这正是我persistence.xmlpersistence-unit项是。此外,我试图改变目录,以便它匹配我的映射类使用的目录。我的测试案例的建立,现在看起来像:

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是否有问题?

+0

什么是您的数据库文件名? 'tsg'? –

+0

@YogendraSingh我想使用内存数据库,所以我不想拥有数据库文件。但是,在生产(远程mysql服务器)上,数据库的*名称*是* tsg *。我是否指定了一些意思,意味着我无意中尝试使用基于文件的数据库? – Edwardr

回答

2

您正在指定URL中的服务器名称,但试图使用内存数据库,这是造成问题的原因。

尝试使用DB网址为:

  jdbc:hsqldb:mem:tsg 

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

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

编辑:要自动创建模式,下面persistence.xml中更新(代替hbm2ddl.auto的hibernate.hbm2ddl.auto)

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

我已经更新了这个问题。感谢您的输入。 – Edwardr

+0

@Edwardr:将persistence.xml中的键名更新为'hibernate.hbm2ddl.auto',即''。 –

+0

是的,我大概在15分钟前就明白了!多烦人的错字!无论如何,这会取得进展,但现在的情况是表格在setup()运行之前创建,所以它们出现在错误的模式中等等。但是,如果我使用类似Derby的东西,那么一切都很完美,所以我可能会做。再次感谢! – Edwardr

0

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

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

嗨,我试图连接到*内存*数据库。根据这些文档:http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html有没有必要指定本地主机在那里? – Edwardr

+0

在这种情况下,您在测试setup()方法中启动的服务器未被使用。 – fredt

+0

好吧,我只是意识到我是一个笨蛋,我正在复制服务器配置。我的persistence.xml中概述的持久性单元正在照顾服务器启动/停止对我,对不对? 'Persistence.createEntityManagerFactory(“TestingPersistenceUnit”);'线足以让服务器启动并运行,对吧? – Edwardr

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(或更改您的映射)。

+0

这是正确的。除非您重命名PUBLIC目录,否则不存在TSG目录。 – fredt

+0

嗨,感谢您的回答。我试图取得进展并更新了我的问题。恐怕还是卡住了。 – Edwardr

+0

为什么你重命名模式?应该不重要。您的映射只能命名一个目录。什么是Hibernate为'@Table(name =“alg_ppc_algorithm_output”,schema =“”,catalog =“tsg”)放在一起的“对象名称”?应该是'tsg..alg_ppc_algorithm_output'。那是你看到的吗? –

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的方案。它甚至可能在单元测试使用包含具有相同名称的表的多个目录时起作用,因为您只需在表名称属性中提供不同的名称。

+0

得到它的工作。但是有一个奇怪的问题;如果我通过Eclipse调用测试,orm.xml是由entitymanager拾取的,但是如果我运行调用mvn clean install orm.xml,则不会使用。查看调试后,我发现问题是由于使用org.hibernate.ejb.Ejb3Configuration中的“root url”引起的。如果Eclipse根url指向找到Meta-inf/orm.xml的test-classes dir。在mvn clean install的情况下,root url指的是domain.jar,由单独的模块生成(项目具有域和存储库层)。由于我不能在域jar中包含测试orm.xml,有没有办法绕过这个? – Developerx