2013-04-19 11 views
5

Ich schreibe häufig Komponententests meiner Datenbank abhängigen Code mit einer In-Memory-HSQL-Datenbank als Test-Datenbank. Vor kurzem habe ich mich entschieden, von 1.8.1.3 auf 2.2.9 zu aktualisieren, um die ROW_NUMBER() - Unterstützung zu nutzen, die im 2.x-Versionszweig hinzugefügt wurde.Komponententests von Hibernate-basierten Code auf hsqldb 1.8.1.3 nicht mehr auf hsqldb 2.2.9

Es scheint, dass in gewisser Weise die neue Version strenger als die alte Version ist. Unter Verwendung von Hibernate (3.6.10) als ORM, könnte ich zum Beispiel ein Configuration Objekt erstellen, um ein erstes SessionFactory zu erstellen, das zum Auffüllen der Testdaten verwenden und dann das Configuration für die zu testende Klasse verwenden, die ihr eigenes SessionFactory erstellt eine Auswahl. Mit hsqldb 1.8.1.3, kein Problem. Mit 2.2.9 werden die Blöcke innerhalb des hsqldb-Codes ausgewählt. Nachfolgend finden Sie eine SSCCE dies demonstrieren:

public void testTwoSessionFactories() throws Exception { 
    boolean withTx = false; 

    AnnotationConfiguration config = new AnnotationConfiguration().addAnnotatedClass(Entity.class); 
    config.setProperty("hibernate.hbm2ddl.auto", "create"); 
    config.setProperty(Environment.DIALECT, HSQLDialect.class.getName()); 
    config.setProperty(Environment.DRIVER, jdbcDriver.class.getName()); 
    config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB"); 
    config.setProperty(Environment.USER, "SA"); 
    config.setProperty(Environment.PASS, ""); 

    SessionFactory sessionFactory1 = config.buildSessionFactory(); 
    Session session = sessionFactory1.openSession(); 

    Transaction tx = null; 
    if (withTx) 
     tx = session.beginTransaction(); 

    session.save(new Entity("one")); 

    if (withTx) 
     tx.commit(); 

    session.flush(); 
    session.close(); 

    config.setProperty("hibernate.hbm2ddl.auto", ""); 
    SessionFactory sessionFactory2 = config.buildSessionFactory(); 
    Session session2 = sessionFactory2.openSession(); 
    List entities = session2.createCriteria(Entity.class).list(); 
    session2.close(); 
} 

Notiere die withTx boolean. Mit HSQLDB 1.8.1.3 kann ich diesen Code mit withTx wahr oder falsch ausführen, und es wird in Ordnung sein. Mit HSQLDB 2.2.9, withTxmuss auf true gesetzt werden, da sonst der Faden in dem .list() Aufruf mit dem folgenden Stapel blockiert wird:

Unsafe.park(boolean, long) line: not available [native method] 
LockSupport.park(Object) line: not available  
CountDownLatch$Sync(AbstractQueuedSynchronizer).parkAndCheckInterrupt() line: not available 
CountDownLatch$Sync(AbstractQueuedSynchronizer).doAcquireSharedInterruptibly(int) line: not available 
CountDownLatch$Sync(AbstractQueuedSynchronizer).acquireSharedInterruptibly(int) line: not available 
CountDownLatch.await() line: not available 
CountUpDownLatch.await() line: not available  
Session.executeCompiledStatement(Statement, Object[]) line: not available 
Session.execute(Result) line: not available 
JDBCPreparedStatement.fetchResult() line: not available 
JDBCPreparedStatement.executeQuery() line: not available  
BatchingBatcher(AbstractBatcher).getResultSet(PreparedStatement) line: 208 
CriteriaLoader(Loader).getResultSet(PreparedStatement, boolean, boolean, RowSelection, SessionImplementor) line: 1953 
CriteriaLoader(Loader).doQuery(SessionImplementor, QueryParameters, boolean) line: 802 
CriteriaLoader(Loader).doQueryAndInitializeNonLazyCollections(SessionImplementor, QueryParameters, boolean) line: 274 
CriteriaLoader(Loader).doList(SessionImplementor, QueryParameters) line: 2542 
CriteriaLoader(Loader).listIgnoreQueryCache(SessionImplementor, QueryParameters) line: 2276 
CriteriaLoader(Loader).list(SessionImplementor, QueryParameters, Set, Type[]) line: 2271  
CriteriaLoader.list(SessionImplementor) line: 119 
SessionImpl.list(CriteriaImpl) line: 1716 
CriteriaImpl.list() line: 347 
EntityTest.testTwoSessionFactories() line: 46 

Was in HSQLDB geändert zwischen 1.8.1.3 und 2.2.9, die erfordert, diesen Code, um das Speichern innerhalb einer Transaktion durchzuführen, und kann ich es ausschalten?

+0

Vielleicht sollten Sie die Leute fragen, die HSQLDB entwickeln. –

+0

Jede Datenbankinteraktion sollte trotzdem innerhalb einer Transaktion erfolgen. Das empfiehlt die Hibernate-Dokumentation. Ich würde den Fehler einfach beheben und sicherstellen, dass Sie immer Transaktionen verwenden. Warum verwenden Sie zwei verschiedene Sitzungsfactories? Es gibt keinen Grund, das zu tun. Eine Sitzungsfabrik ist ein schwergewichtiges Objekt, das ein für allemal erstellt werden sollte. +1 für den Test der eindeutigen Einheit. –

+0

@JBNizet Re: Transaktionen, im Produktionscode tue ich das immer, aber im Test-Setup-Code bin ich lockerer, weil ich denke, dass es nur Krempel zum Test hinzufügt. Nicht so schlimm, dass ich es nicht ändern kann! – sharakan

Antwort

8

HSQLDB 1.8.x verwendet READ UNCOMMITTED für Zeilen, die von einer anderen Transaktion hinzugefügt oder geändert wurden.

HSQLDB 2.x verwendet READ COMMITTED (standardmäßig) oder SERIALIZABLE Isolationsstufe. Daher muss eine Transaktion festgeschrieben werden, bevor ihre Änderungen sichtbar sind. Es gibt auch die transaction model zu beachten.

Der Standardwert transaction model ist LOCKS, der eine Tabelle sperrt, die geändert wird, bis die Transaktion festgeschrieben wird. Sie können stattdessen MVCC model verwenden, wodurch andere Sitzungen aus der Tabelle gelesen und Zeilen geändert werden können, die nicht geändert wurden. Sie können dieses Modell mit einem URL property verwenden.

config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB;hsqldb.tx=mvcc"); 
+0

Das klingt so, ich werde es überprüfen. Gibt es eine Möglichkeit, eine Eigenschaft zu ändern, sodass ich auf Ebene des Verbindungspools zu READ UNCOMMITTED wechseln kann? – sharakan

+0

READ UNCOMMITTED wird in neueren Versionen nicht unterstützt. – fredt

+0

Verstanden, ich verließ mich auf das schmutzige 'Feature', über das sie in [den Dokumenten] sprechen (http://hsqldb.org/doc/guide/sessions-chapt.html#snc_tx_tx_cc). Ich werde in meinem Test explizite Transaktionen verwenden, danke, dass Sie mir den Weg gezeigt haben! – sharakan