2012-04-16 21 views
5

JUnit、OpenEJB、Eclipselink、およびHSQLDBを使用したテストフレームワークがあります。これまでのところすべてがうまくいき、サービス層のテストは簡単です。しかし、今度は、テーブル(サービス層、entitymanagerを使用)で大量インポートを行うときや、サービスメソッドで複数のエンティティをリストに永続化するときに問題が発生しています。JUnitテストにおけるHSQLDB主キー違反エラー

これはWEIRD PARTです:テストがMavenのコマンドラインから十分に速いワークステーションで実行されていれば、私たちのテストは壊れそうです。 Eclipse IDEでテストを実行すると、すべてが正常ですが、ランダムに、失敗することもあります。私たちは、テストが実行されるスピードと何かが関係するかもしれないと思っています。基本的に、すでに存在するidを持つエンティティを追加しようとしているので、例外は十分に簡単です。テストデータとhsqldbデータベースを複数回チェックしました。私たちが使用しようとしているidを持つ既存の行はありません。それでもhsqldbはある時点で主キーの例外をスローします。私たちのログから、競合するIDは必ずしも同じではないことがわかります。300015または300008かもしれません。

私たちはここにいます。 HSQLDBのトランザクションや何か他のものが失効したデータの原因となることがありますか?

HSQLDB 2.2.8、Eclipselink 2.3.0、およびOpenEJB 4.0.0-beta2を使用しています。

我々は次のようにマッピングされたエンティティを追加しようとしている関係:

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

ルート例外は次のとおりです。

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:

私は主キーの生成方法を変更しましたGenerationType.AUTO(デフォルトでTABLE戦略を使用していると思われる)からIDENTITYこの後も、私たちの大衆は引き続き成功するようです。私はまだHSQLDBがなぜTABLE戦略と「同期していない」のかは分かりません。私たちのテストフレームワークがバグであるからといって、私はjpaのエンティティを変更したくないでしょう:)

+0

どのようなバージョンのHSQLDBを使用していますか? JUnitはデータベースに大きなトランザクション・ロールバック・ロードを課すため、おそらくバグや、HSQLDBを高速かつ小規模に保つために行われた既知のエンジニアリング・トレードオフのいずれかに陥っているでしょう。データベース設定とEclipselinkがIDテーブルを構成し管理する方法の組み合わせかもしれません。常にバージョン番号を投稿することをお勧めします。 –

+0

バージョン番号を元の投稿に編集します。私はHSQLDB 2.2.8 Eclipselink 2.3.0とOpenEJB 4.0.0-beta2を使用しています。また、EntityはIDENTITYカラムを使用していません。代わりに、戦略はAUTOで、これはHSQLDBのTABLE戦略を使用していると思います。 –

+0

問題を見つけて対処するのにどれだけ気を配っていますか? TABLE(またはEclipselinkのTABLEであるAUTO)からSequenceまたはIDENTITYに切り替えると、おそらくこの問題が解消されます。なぜ起こっているのかを理解するには、トランザクションと隔離とロールバックの設定とバグのキャッシングなどの苦しい掘り下げが必要です。 –

答えて

0

ほとんどの場合、多くの行をMEMORYテーブルにインポートするときにメモリが不足しています。

メモリ割り当てを増やすか、この特定のテーブルをCACHEDテーブルとして定義する必要があります。

更新:CACHEDテーブルは永続的なデータベースではなく、すべてのインメモリ・データベースで使用することができます:

CREATE CACHED TABLE mytable ... 

または既存のテーブルのために:

SET TABLE mytable TYPE CACHED 

がUPDATE:

これがOOMに起因していない場合は、世代戦略の変更が確認されると、生成戦略が生成された主キー値をsomで増分していない可能性がありますeポイント。アイデンティティ戦略は、生成された値を作成するためにデータベースに依存しています。これはうまく動作します。

+0

試してみる価値があるかもしれません。 1つのテーブルをHSQLDBにキャッシュとして定義するにはどうすればよいですか? –

+0

が更新されました – fredt

+0

プライマリキーの生成方法をGenerationType.AUTO(デフォルトではTABLE-strategyを使用しているようです)からIDENTITYに変更しました。この後も、私たちの大衆は引き続き成功するようです。私はまだHSQLDBがなぜTABLE戦略と「同期していない」のかについてはまだ分かりません。 –

0

allocationSizeが比較的高速なプラットフォーム上でボトルネックを定義している可能性があります。 つまり デフォルトのGenerationType.AUTOに設定すると、テーブルのEclipseLinkに違反すると、割り当てられた値までIDがキャッシュされます。次に、最後に割り当てられた値を確認するためにジェネレータを検索します。 IDの次のセットがキャッシュされる前に、allocationSizeの周りでルックアップが発生した場合、キャッシュを更新する前にeclipseリンクがキャッシュの最後のIDを2回割り振り、両方を使用しようとする競合状態になる可能性があります。両方の挿入が失敗し、ロールバックされます。あなたは、あなたの割り当てキャッシュがインクリメントされなければならないとき、これは周りに起こるかどうかを確認する必要がありますすることができ、おそらくチェックのようなものを使用すると、デバッガフリークなら、あなたはHSQLDBを再構築することができますintegrity constraint violation: unique constraint or index violation のために行動

+0

興味深いことに、allocationSizeを25から例えば50に増やすことは、テストごとに数百のエンティティを作成する場合でも、JUnitテストの問題を解決するようです。テストのために妥協をするのはちょっとうんざりです。 – Kimi

0

を変更する可能性がある場合デバッグモードを開き、変数compareにブレークポイントcompare == 0の条件が割り当てられた行にブレークポイントをorg.hsqldb.index.IndexAVLMemory#insertに設定します。

エラーのある行(たとえば重複するもの)は引数として渡されます。

関連する問題