2012-11-13 44 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