ListResultsConsumer:发现重复行并指定了“ASSERT”

问题描述 投票:0回答:1
  • JDK 17
  • JPA 3.1
  • 休眠 6.2

将 spring boot 2.x 升级到 3.x(涉及从 hibernate 5.x 升级到 6.x)后,我收到此错误:

org.springframework.orm.jpa.JpaSystemException: Duplicate row was found and `ASSERT` was specified

可重现的示例

(下面的例子中

MyEntity
称为
Question

https://github.com/RobertHeim/so-duplicate-row

背景

我的测试运行良好,但最后一行抛出异常:

Language lang = langRepository.findOneByLocale(locale).orElse(null);
final var id = new MyEntityI18nId(
        em.getReference(MyEntity.class, id),
        lang
);
var byIds = myRepo.findAllById(Set.of(id));
assertThat(byIds).hasSize(1);
// fine until here

myRepo.findById(id); // throws org.springframework.orm.jpa.JpaSystemException: Duplicate row was found and `ASSERT` was specified

我不明白这个例外意味着什么。它首先感觉像是一个错误,因为我认为它告诉我在尝试运行时数据库中有重复行

findById(id)
,但我证明在语句之前没有重复行。此外,数据库上有一个独特的约束来保证它,所以不知何故这不可能是真的。

现在我想知道该消息的实际含义。

我尝试创建一个最小的可重现示例,结果发现当我从另一个表中删除数据时错误消失了。从那里我能够理解,这些相关数据是急切地获取的,并且它本身也急切地获取

MyEntity
(参见示例中的
QuestionI18n.QuestionI18nId.question
)。我是否理解正确,该错误想告诉我,我现在在结果集中(而不是在数据库中)得到了同一行?或者它想告诉我什么?

编辑

因此,通过进一步调试,我发现

ListResultsConsumer
及其定义
UniqueSemantic
的枚举
ASSERT
的定义评论为:

应用内存中的重复检查,当发现重复项时抛出 HibernateException

它已在 hibernate 6.x 中引入,这解释了为什么我没有碰巧在 5.x 上看到该错误。它还让我更有信心,我对错误消息的理解是正确的 - hibernate 尝试告诉我,在查询期间,负载图想要查询一个实体两次。但这是一个严重错误还是只是一个提示?因为我希望 hibernate 能够优化查询,而不是真正加载它两次。不管怎样,我不太有信心合适的修复是什么。

而且我仍然不太明白为什么这个错误发生在

findById
而不是
findByIds
,据我所知,对于相同的输入 id 应该表现完全相同。

hibernate jpa
1个回答
0
投票

我刚刚解决了一个类似的问题,我遇到了同样的错误,由于这里没有答案,我将添加我的解决方案,希望它能为您指明正确的方向。

就我而言,错误已经在

findAll(Pageable pageable)
方法上抛出,并且您可能会注意到我正在使用分页。我的错误仅针对某些
Pageable
抛出,因此有时该方法运行良好,有时会抛出错误。

我的问题出在

MyEntity
。我设置了以下代码:

@Entity
@Table("MyEntity")
public class MyEntity {
  ...

  @OneToOne
  @JoinColumn(name = "ID", referencedColumnName = "ID")
  private MyOtherEntity otherEntity;
}

问题在于,与 MyOtherEntity 的连接实际上应该是

@OneToMany
。由于
@OneToOne
默认情况下是急切加载的(就像
@OneToMany
一样),这意味着当我执行
myEntityRepo.findAll(pageable)
时,如果任何
MyEntity
包含 2 个或更多
MyOtherEntity
,则会抛出错误。只要页面上的所有
MyEntity
包含 1 个或更少
MyOtherEntity
,就不会引发异常。

所以,我的解决方案是将其更改为以下内容:

@OneToMany(fetch = FetchType.LAZY) //LAZY fetch type for good measure, not necessary
@JoinColumn(name = "ID", referencedColumnName = "ID")
private List<MyOtherEntity> otherEntities;
© www.soinside.com 2019 - 2024. All rights reserved.