JUnit测试中出现HSQLDB主键违规错误

iibxawm4  于 2022-11-11  发布在  其他
关注(0)|答案(3)|浏览(136)

我们有一个使用JUnit、OpenEJB、Eclipselink和HSQLDB的测试框架。到目前为止一切都运行良好,测试服务层也是轻而易举的事。然而,现在,当我们在表上进行批量导入(使用服务层、实体管理器)时,或者例如在服务方法中多次将实体持久化到列表中时,我们遇到了问题。
这是一个奇怪的部分:我们的测试似乎只有在足够快的工作站上使用Maven从命令行运行测试时才会中断。当我通过EclipseIDE运行测试时,一切都很好,但有时也会随机失败。我们怀疑这可能与测试运行的速度有关。这个异常很简单,因为它告诉我们,我们正在尝试添加一个具有已经存在的id的实体。我们已多次检查测试数据和hsqldb数据库。不存在具有我们要使用的ID的预先存在的行。但hsqldb仍在某个时候引发主键异常错误。从日志中可以看到,冲突ID并不总是相同的,它可能是300015或300008。
我们已经无计可施了。这会不会与HSQLDB的事务有关,或者是其他什么原因导致了数据失效?
我们使用的是HSQLDB 2.2.8、Eclipse链接2.3.0和OpenEJB 4.0.0-beta 2。
我们尝试将实体添加到的关系Map如下:

@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。在此之后,我们的mass持久化似乎可以正常工作。我仍然不知道为什么HSQLDB与TABLE策略“不同步”。我不想仅仅因为我们的测试框架有缺陷就更改我们的jpa实体:)

5fjcxozz

5fjcxozz1#

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

mklgxw1f

mklgxw1f2#

最有可能的情况是,在将大量行导入MEMORY表时内存不足。
您应该增加内存分配或将此特定表定义为CACHED表。
更新:CACHED表可用于持久性数据库,而不能用于全内存数据库:

CREATE CACHED TABLE mytable ...

或对于现有表:

SET TABLE mytable TYPE CACHED

最新消息:
如果这不是由OOM引起的,正如更改生成策略所证实的那样,则似乎生成策略在某个点上可能没有递增生成的主键值。标识策略依赖于数据库来创建生成的值,这一点可以正常工作。

agyaoht7

agyaoht73#

对于integrity constraint violation: unique constraint or index violation如果您是一个调试器怪胎,您可以在调试模式下重建hsqldb,并在org.hsqldb.index.IndexAVLMemory#insert中的某行设置断点,其中变量compare已被分配了断点compare == 0上的条件。
错误的行(例如重复的行)将是作为参数传递的行。

相关问题