2012-04-16 4 views
5

Wir haben ein Test-Framework mit JUnit, OpenEJB, Eclipselink und HSQLDB. Bis jetzt hat alles funktioniert, und das Testen der Service-Ebene ist ein Kinderspiel. Jetzt treten jedoch Probleme auf, wenn Massenimporte für eine Tabelle (unter Verwendung der Service-Schicht, des Entitäts-Managers) durchgeführt werden oder wenn beispielsweise Entitäten in einer Servicemethode mehrfach in einer Liste gespeichert werden.HSQLDB Primärschlüsselverletzung in JUnit Tests

Das ist der seltsame Teil: Unsere Tests scheinen nur zu brechen, wenn Tests auf einer schnell genug Workstation von der Befehlszeile mit Maven ausgeführt werden. Wenn ich die Tests über die Eclipse-IDE durchführe, ist alles in Ordnung, aber manchmal kommt es auch zufällig dazu. Wir vermuten, dass es etwas mit der Geschwindigkeit zu tun haben könnte, mit der die Tests durchgeführt werden, so seltsam es klingt. Die Ausnahme ist einfach genug, weil sie uns im Grunde sagt, dass wir versuchen, eine Entität mit einer bereits existierenden ID hinzuzufügen. Wir haben mehrmals unsere Testdaten und die hsqldb-Datenbank überprüft. Es gibt keine bereits vorhandenen Zeilen mit IDs, die wir verwenden möchten. Immer noch hsqldb löst die Primärschlüsselausnahme irgendwann aus. Aus unseren Protokollen können wir sehen, dass die in Konflikt stehende ID nicht immer die gleiche ist, es könnte 300015 oder 300008 sein.

Wir sind hier am Ende unserer Weisheit. Könnte es etwas mit HSQLDB-Transaktionen zu tun haben oder etwas anderes, das veraltete Daten verursacht?

Wir verwenden HSQLDB 2.2.8, Eclipselink 2.3.0 und OpenEJB 4.0.0-beta2.

Die Beziehung wir versuchen, Entitäten hinzufügen, wie folgt zugeordnet wird:

@OneToMany(mappedBy = "invoice", cascade = CascadeType.PERSIST) 
private List<InvoiceBalance> getInvoiceBalanceHistory() { 
    if (invoiceBalanceHistory == null) { 
     this.invoiceBalanceHistory = new ArrayList<InvoiceBalance>(); 
    } 
    return invoiceBalanceHistory; 
} 

Die Wurzel Ausnahme ist:

Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10492 table: INVOICEBALANCE 
at org.hsqldb.jdbc.Util.sqlException(Unknown Source) 
at org.hsqldb.jdbc.Util.sqlException(Unknown Source) 
at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source) 
at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source) 
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:831) 
... 82 more 
Caused by: org.hsqldb.HsqlException: integrity constraint violation: unique constraint or index violation; SYS_PK_10492 table: INVOICEBALANCE 
at org.hsqldb.error.Error.error(Unknown Source) 
at org.hsqldb.Constraint.getException(Unknown Source) 
at org.hsqldb.index.IndexAVLMemory.insert(Unknown Source) 
at org.hsqldb.persist.RowStoreAVL.indexRow(Unknown Source) 
at org.hsqldb.TransactionManager2PL.addInsertAction(Unknown Source) 
at org.hsqldb.Session.addInsertAction(Unknown Source) 
at org.hsqldb.Table.insertSingleRow(Unknown Source) 
at org.hsqldb.StatementDML.insertSingleRow(Unknown Source) 
at org.hsqldb.StatementInsert.getResult(Unknown Source) 
at org.hsqldb.StatementDMQL.execute(Unknown Source) 
at org.hsqldb.Session.executeCompiledStatement(Unknown Source) 
at org.hsqldb.Session.execute(Unknown Source) 

EDIT:

änderte ich die primäre Strategie Schlüsselgenerierung von GenerationType.AUTO (das die TABLE-Strategie standardmäßig zu verwenden scheint) zu IDENTITY. Danach scheint unsere Masse bestehen geblieben zu sein. Ich weiß immer noch nicht, warum HSQLDB mit der TABLE-Strategie "nicht mehr synchron läuft". Ich würde unsere jpa-Entitäten nicht ändern wollen, nur weil unser Testframework fehlerhaft ist.

+0

Welche Version von HSQLDB verwenden Sie? JUnit verursacht eine schwere Rollback-Last für die Datenbank und Sie werden wahrscheinlich in einen Bug oder einen bekannten technischen Kompromiss geraten, der dafür sorgt, dass die HSQLDB schnell und klein bleibt. Oder vielleicht eine Kombination Ihrer Datenbankeinstellungen und wie Eclipselink die Identitätstabelle konfiguriert und verwaltet. Es ist immer eine gute Idee, Versionsnummern zu veröffentlichen. –

+0

Ich werde die Versionsnummern auf den ursprünglichen Beitrag bearbeiten. Ich verwende HSQLDB 2.2.8 Eclipselink 2.3.0 und OpenEJB 4.0.0-beta2. Außerdem verwendet die Entität keine IDENTITY-Spalte, stattdessen ist die Strategie AUTO, was meiner Meinung nach die TABLE-Strategie für HSQLDB verwendet. –

+0

Wie sehr interessiert es Sie, das Problem zu finden, anstatt es zu umgehen? Der Wechsel von TABLE (oder AUTO, was TABLE für Eclipselink ist) zu Sequence oder IDENTITY wird das Problem wahrscheinlich beseitigen. Herauszufinden, warum es passiert, wird viele schmerzhafte Suche nach Transaktions- und Isolierungs- und Rollback-Einstellungen und das Zwischenspeichern von Fehlern beinhalten und so weiter. –

Antwort

0

Wahrscheinlich haben Sie nicht genügend Arbeitsspeicher, während Sie viele Zeilen in eine MEMORY Tabelle importieren.

Sie sollten die Speicherzuweisung erhöhen oder diese bestimmte Tabelle als CACHED-Tabelle definieren.

Update: CACHED Tabellen können in persistente Datenbanken verwendet werden, nicht in All-in-Memory-Datenbanken:

CREATE CACHED TABLE mytable ... 

oder für eine vorhandene Tabelle:

SET TABLE mytable TYPE CACHED 

UPDATE:

Wenn dies nicht durch OOM verursacht wird, wie es die Änderung der Generierungsstrategie bestätigt, dann scheint die Generierungsstrategie den generierten Primärschlüsselwert bei Som nicht zu erhöhen e Punkt. Die Identitätsstrategie beruht auf der Datenbank, um den generierten Wert zu erstellen, was gut funktioniert.

+0

Könnte einen Versuch wert sein. Wie kann ich eine einzelne Tabelle als zwischengespeichert in HSQLDB definieren? –

+0

Antwort aktualisiert – fredt

+0

Ich habe die Generierungsstrategie für den Primärschlüssel von GenerationType.AUTO (die die TABLE-Strategie standardmäßig zu verwenden scheint) zu IDENTITY geändert. Danach scheint unsere Masse bestehen geblieben zu sein. Ich weiß immer noch nicht, warum HSQLDB mit der TABLE-Strategie "nicht mehr synchron läuft". –

0

Es könnte sein, dass Ihre allocationSize einen Engpass auf relativ schnellen Plattformen oder gelegentlich definiert. , d. H. Wenn standardmäßig auf GenerationType.AUTO gesetzt wird, die defaulyrs zu Tabelle EclipseLink wird cache ID bis zu den zugewiesenen Wert. Es wird dann nach dem Generator gesucht, um seinen letzten zugewiesenen Wert zu bestätigen. Wenn ein Suchvorgang um den Rand der allocationSize vor dem Zwischenspeichern des nächsten ID-Satzes durchgeführt wird, tritt möglicherweise eine Race-Bedingung auf, bei der eclipse link die letzte ID im Cache zweimal zuweist, bevor sie den Cache aktualisiert und versucht, beide zu verwenden Einfügen und beide Inserts fehlschlagen und sind Rollback. Wenn Sie können, sollten Sie überprüfen, um zu sehen, ob dies um passiert, wenn Ihre Zuweisung Cache sollte erhöht werden, aber vielleicht diese Art von Kontrolle könnte das Verhalten

+0

Interessanterweise scheint eine Erhöhung der allocationSize von 25 auf 50 das Problem in den JUnit-Tests zu lösen - selbst wenn Hunderte von Entitäten pro Test erstellt werden. Es ist ein bisschen schlecht, Kompromisse aufgrund von Tests einzugehen. – Kimi

0

Für integrity constraint violation: unique constraint or index violation ändern Wenn Sie ein Debugger-Freak sind, können Sie hsqldb Wiederaufbau in Debug-Modus und setzen Sie einen Haltepunkt in org.hsqldb.index.IndexAVLMemory#insert an einer Zeile, wo die Variable compare mit einer Bedingung auf den Haltepunkt compare == 0 zugewiesen wurde.

Die fehlerhafte Zeile (z. B. die doppelte) wird als Argument übergeben.