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

Java JUnit测试中的HSQLDB主键冲突错误,java,jakarta-ee,junit,eclipselink,hsqldb,Java,Jakarta Ee,Junit,Eclipselink,Hsqldb,我们有一个使用JUnit、OpenEJB、Eclipselink和HSQLDB的测试框架。到目前为止,一切都很顺利,测试服务层是轻而易举的事。然而,现在我们在对表进行大规模导入(使用服务层entitymanager)或例如在服务方法中将实体多次持久化到列表时遇到了问题 这是奇怪的部分:我们的测试似乎只有在使用Maven的命令行在足够快的工作站上运行时才会中断。当我通过EclipseIDE运行测试时,一切正常,但有时,随机地,它也会失败。我们怀疑这可能与测试运行的速度有关,尽管听起来很奇怪。这个异

我们有一个使用JUnit、OpenEJB、Eclipselink和HSQLDB的测试框架。到目前为止,一切都很顺利,测试服务层是轻而易举的事。然而,现在我们在对表进行大规模导入(使用服务层entitymanager)或例如在服务方法中将实体多次持久化到列表时遇到了问题

这是奇怪的部分:我们的测试似乎只有在使用Maven的命令行在足够快的工作站上运行时才会中断。当我通过EclipseIDE运行测试时,一切正常,但有时,随机地,它也会失败。我们怀疑这可能与测试运行的速度有关,尽管听起来很奇怪。这个异常非常简单,因为它告诉我们,我们正在尝试添加一个已经存在id的实体。我们已经多次检查了测试数据和hsqldb数据库。没有我们尝试使用的id为的预先存在的行。hsqldb仍然会在某个时刻抛出主键异常。从我们的日志中,我们可以看到冲突ID并不总是相同的,它可能是300015或300008

我们在这方面束手无策。它可能与HSQLDB的事务或其他导致陈旧数据的事情有关吗

我们正在使用HSQLDB2.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;
}
编辑:


我将主键生成策略从GenerationType.AUTO(默认情况下似乎使用表策略)更改为IDENTITY。在这之后,我们的群众似乎没有失败。我仍然不知道为什么HSQLDB与表策略“不同步”。我不想仅仅因为我们的测试框架有缺陷就更改我们的jpa实体:)

很可能,在将大量行导入
内存
表时内存不足

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

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

CREATE CACHED TABLE mytable ...
或对于现有表:

SET TABLE mytable TYPE CACHED
更新:


如果这不是由OOM引起的,正如更改生成策略所确认的那样,那么生成策略似乎在某个点上不会增加生成的主键值。身份策略依赖于数据库来创建生成的值,这很好。

可能是您的allocationSize在相对快速的平台上或偶尔定义了瓶颈。 即 默认为GenerationType.AUTO时,表EclipseLink的默认值将缓存ID,直到分配的值。然后,它将查找生成器以确认其最后分配的值。
如果在缓存下一组ID之前在allocationSize的边缘进行了查找,那么您可能会遇到竞争条件,其中eclipse link在更新缓存之前将缓存中的最后一个ID分配两次,并尝试同时使用这两个ID进行插入,而这两个插入都失败并回滚。如果可以,您应该检查在分配缓存应该增加时是否会发生这种情况,但这种检查可能会改变
完整性约束冲突:唯一约束或索引冲突的行为
如果你是一个调试器爱好者,你可以在调试模式下重建hsqldb,并在
org.hsqldb.index.IndexAVLMemory#insert
中的一行设置一个断点,在该行中变量
compare
被分配了断点
compare==0


错误行(例如重复行)将作为参数传递。

可能值得一试。如何将单个表定义为缓存在HSQLDB中?我将主键生成策略从GenerationType.AUTO(默认情况下似乎使用表策略)更改为IDENTITY。在这之后,我们的群众似乎没有失败。我仍然不知道为什么HSQLDB与表策略“不同步”。您使用的是什么版本的HSQLDB?JUnit对数据库施加了沉重的事务回滚负载,您可能会遇到一个bug,或者是为了保持HSQLDB的快速和小型而进行的已知工程权衡。或者结合数据库设置和Eclipselink如何配置和管理标识表。发布版本号总是个好主意。我会将版本号编辑到原始帖子中。我正在使用HSQLDB2.2.8 Eclipselink 2.3.0和OpenEJB 4.0.0-beta2。此外,实体没有使用标识列,而是使用自动策略,我认为这是在HSQLDB上使用表策略。您对发现问题和解决问题有多关心?从TABLE(或AUTO,这是Eclipse的TABLE)切换到Sequence或IDENTITY可能会解决这个问题。要弄清楚为什么会发生这种情况,需要通过事务、隔离、回滚设置、缓存bug等等进行大量痛苦的挖掘。这是当前的解决方案。这仅仅意味着100多个实体最初使用的是表策略,少数需要这些类型测试的异常现在是标识。我希望在这方面有一些一致性,但这听起来确实是一个非常耗时的问题。当实现在应用服务器上运行时,仅仅为了一些随机测试而更改ID列生成策略听起来有点错误。。。如果你用数据文件而不是内存会怎么样?例如,使用如下连接字符串jdbc:hsqldb:file:data/db/db;关机=真;hsqldb.write_delay_millis=0另请参见:有趣的是,将allocationSize从25增加到(比如)50似乎可以解决JUnit测试中的问题,即使每个测试创建数百个实体。因为测试而做出妥协有点糟糕。
SET TABLE mytable TYPE CACHED