2012-04-16 14 views
5

Abbiamo un framework di test che utilizza JUnit, OpenEJB, Eclipselink e HSQLDB. Tutto ha funzionato fino ad ora, e testare il livello di servizio è un gioco da ragazzi. Ora, tuttavia, si verificano problemi durante l'importazione di massa su una tabella (utilizzando il livello di servizio, entitymanager) o, ad esempio, le entità persistenti in un elenco più volte in un metodo di servizio.Errore di violazione della chiave primaria HSQLDB nei test JUnit

QUESTA E 'LA PARTE DEGLI OBIETTIVI: I nostri test sembrano interrompersi solo se i test vengono eseguiti su una workstation sufficientemente veloce dalla riga di comando con Maven. Quando eseguo i test con Eclipse IDE, tutto va bene, ma a volte, casualmente, fallisce anche. Sospettiamo che possa avere qualcosa a che fare con la velocità con cui vengono eseguiti i test, per quanto strano possa sembrare. L'eccezione è abbastanza semplice perché in pratica ci dice che stiamo cercando di aggiungere un'entità con un ID già esistente. Abbiamo più volte controllato i nostri dati di test e il database hsqldb. Non ci sono righe preesistenti con ID che stiamo cercando di utilizzare. Ancora hsqldb lancia l'eccezione chiave primaria ad un certo punto. Dai nostri registri possiamo vedere che l'ID in conflitto non è sempre lo stesso, potrebbe essere 300015 o 300008.

Siamo alla fine del nostro spirito qui. Potrebbe avere qualcosa a che fare con le transazioni di HSQLDB o qualcos'altro che causa dati obsoleti?

Utilizziamo HSQLDB 2.2.8, Eclipselink 2.3.0 e OpenEJB 4.0.0-beta2.

La relazione che stiamo cercando di aggiungere entità è mappato come segue:

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

L'eccezione principale è:

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:

ho cambiato la strategia di generazione della chiave primaria da GenerationType.AUTO (che sembra utilizzare la strategia TABLE per impostazione predefinita) a IDENTITY. Dopo questo, la nostra massa persiste sembra funzionare senza fallire. Non so ancora perché HSQLDB vada "fuori sincrono" con la strategia TABLE. Non vorrei cambiare le nostre entità jpa solo perché il nostro framework di test è bacato :)

+0

Quale versione di HSQLDB stai utilizzando? JUnit impone un carico pesante di rollback della transazione sul database e probabilmente si sta verificando un bug o un compromesso di progettazione noto per mantenere HSQLDB veloce e piccolo. O forse una combinazione delle impostazioni del database e di come Eclipselink configura la tabella delle identità e la gestisce. È sempre una buona idea pubblicare i numeri di versione. –

+0

Modificherò i numeri di versione nel post originale. Sto usando HSQLDB 2.2.8 Eclipselink 2.3.0 e OpenEJB 4.0.0-beta2. Anche l'entità non sta usando una colonna IDENTITÀ, invece la strategia è AUTO che penso stia usando la strategia TABLE su HSQLDB. –

+0

Quanto ti preoccupi di trovare il problema rispetto a lavorare intorno ad esso? Passare da TABLE (o AUTO, che è TABLE per Eclipselink) a Sequence o IDENTITY probabilmente eliminerà il problema. Capire perché sta accadendo comporterà molti dolorosi scavi attraverso le impostazioni di transazione e isolamento e di rollback e bug nella cache e così via. –

risposta

0

Molto probabilmente, si sta esaurendo la memoria durante l'importazione di un sacco di righe in una tabella MEMORY.

È necessario aumentare l'allocazione di memoria o definire questa tabella specifica come tabella CACHED.

Aggiornamento: CACHED tabelle possono essere utilizzati in banche dati persistenti, non in all-in-memory database:

CREATE CACHED TABLE mytable ... 

o per una tabella esistente:

SET TABLE mytable TYPE CACHED 

UPDATE:

Se ciò non è causato da OOM, poiché la modifica della strategia di generazione conferma, sembra che la strategia di generazione potrebbe non incrementare il valore della chiave primaria generata a som punto. La strategia di identità si basa sul database per creare il valore generato, che funziona bene.

+0

Potrebbe valere la pena provare. Come posso definire una singola tabella come memorizzata nella cache in HSQLDB? –

+0

answere updated – fredt

+0

Ho modificato la strategia di generazione della chiave primaria da GenerationType.AUTO (che sembra utilizzare la strategia TABLE per impostazione predefinita) a IDENTITY. Dopo questo, la nostra massa persiste sembra funzionare senza fallire. Non so ancora perché HSQLDB vada "fuori sincrono" con la strategia TABLE. –

0

Potrebbe essere possibile che l'allocazioneSize stia definendo un collo di bottiglia su piattaforme relativamente veloci o occasionalmente. , ad esempio Se impostato su GenerationType.AUTO, che fa riferimento alla tabella EclipseLink memorizzerà l'ID cache fino al valore assegnato. Quindi cercherà il generatore per confermare il suo ultimo valore assegnato. Se una ricerca è avvenuta intorno al limite di allocazione prima che il prossimo set di ID venga memorizzato nella cache, è possibile che si verifichi una condizione di competizione in cui il link eclipse alloca l'ultimo id nella cache due volte prima che aggiorni la cache e tenti di utilizzare entrambi per inserire e entrambi gli inserimenti falliscono e sono rolledback. Se è possibile si dovrebbe controllare per vedere se questo accade in giro quando la cache di allocazione dovrebbe essere incrementato, ma forse quel tipo di controllo potrebbe modificare il comportamento

+0

È interessante notare come aumentare l'allocazione Dimensione da 25 a, 50 sembra risolvere il problema nei test JUnit, anche quando si creano centinaia di entità per test. È una specie di risucchio per fare compromessi a causa dei test. – Kimi

0

Per integrity constraint violation: unique constraint or index violation Se sei un maniaco del debugger, è possibile ricostruire in hsqldb modalità di debug e impostare un punto di interruzione in org.hsqldb.index.IndexAVLMemory#insert in corrispondenza di una riga in cui la variabile compare è stata assegnata con una condizione sul punto di interruzione compare == 0.

La riga errata (quella duplicata per esempio) sarà quella passata come argomento.

Problemi correlati