JUnit测试中的HSQLDB主键冲突错误

问题描述 投票:6回答:3

我们有一个使用JUnit,OpenEJB,Eclipselink和HSQLDB的测试框架。到目前为止,一切都运行良好,测试服务层是一件轻而易举的事。但是,现在我们在表上进行批量导入(使用服务层,实体管理器)或者在服务方法中多次将实体持久化到列表时遇到问题。

这是最重要的部分:我们的测试似乎只有在测试是在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)

编辑:

我将主键生成策略从GenerationType.AUTO(默认情况下似乎使用TABLE策略)更改为IDENTITY。在此之后,我们的群众似乎坚持不懈地工作。我仍然不知道为什么HSQLDB与TABLE策略“不同步”。我不想因为我们的测试框架有问题而改变我们的jpa实体:)

java java-ee junit eclipselink hsqldb
3个回答
0
投票

您的allocationSize可能会在相对较快的平台上或偶尔定义瓶颈。即,默认为GenerationType.AUTO,它默认为表EclipseLink将缓存ID到分配的值。然后它将查找生成器以确认其最后分配的值。如果在缓存下一组ID之前在allocationSize的边缘周围发生了查找,那么您可能会遇到竞争条件,其中eclipse链接在更新缓存之前两次在缓存中分配最后一个id并尝试将两者用于插入两个插入失败并回滚。如果你可以,你应该检查一下当你的分配缓存应该增加时是否会发生这种情况,但是这种检查可能会改变行为


0
投票

最有可能的是,在将大量行导入MEMORY表时,内存不足。

您应该增加内存分配或将此特定表定义为CACHED表。

更新:CACHED表可以在持久数据库中使用,而不是在所有内存数据库中使用:

CREATE CACHED TABLE mytable ...

或者对于现有表格:

SET TABLE mytable TYPE CACHED

更新:

如果这不是由OOM引起的,因为更改生成策略确认,那么生成策略似乎可能不会在某个时刻递增生成的主键值。身份策略依赖于数据库来创建生成的值,这可以正常工作。


0
投票

对于integrity constraint violation: unique constraint or index violation如果您是调试器怪人,可以在调试模式下重建hsqldb并在org.hsqldb.index.IndexAVLMemory#insert中设置一个断点,该行在变量compare已经为断点compare == 0指定了条件。

有缺陷的行(例如,重复的行)将作为参数传递。

© www.soinside.com 2019 - 2024. All rights reserved.