You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hibernate Envers审计一对一关联时触发NonUniqueResultException

解决Hibernate Envers查询A审计记录时的NonUniqueResultException异常

问题根源

查询A的审计记录时,Hibernate Envers会自动尝试加载其关联的B的审计数据。由于你的b_audit表保留了对已删除A实体的历史关联,导致多条B审计记录引用同一个A旧实体,而一对一映射要求关联结果必须唯一,因此触发了NonUniqueResultException。

解决方案

方案1:修改审计查询,仅加载A的实体数据

通过指定查询投影,强制Envers只返回A的实例,不初始化任何关联的审计实体,彻底避免对B的审计查询:

AuditQuery auditQuery = auditReader.createQuery()
        .forRevisionsOfEntity(ClassA.class, false, true)
        .add(AuditEntity.id().in(entityId))
        .addProjection(AuditEntity.selectEntity(false));

selectEntity(false)参数会告诉Envers仅构建并返回A的对象实例,跳过所有关联实体的加载逻辑,从根源解决异常问题。

方案2:同时获取A实体与修订信息(可选)

如果需要同时获取修订号、修订时间等审计元数据,可以在投影中添加对应的字段:

AuditQuery auditQuery = auditReader.createQuery()
        .forRevisionsOfEntity(ClassA.class, false, true)
        .add(AuditEntity.id().in(entityId))
        .addProjection(AuditEntity.selectEntity(false))
        .addProjection(AuditEntity.revisionNumber())
        .addProjection(AuditEntity.revisionTimestamp());

此时查询结果为Object[]数组,结构为:[A实例, 修订号, 修订时间戳],同样不会加载关联的B审计数据。

验证说明

删除b_audit中的旧关联记录后异常消失,是因为此时每个A旧实体仅对应一条B审计记录,一对一查询能拿到唯一结果,但这种方式破坏了你保留历史关联的需求,因此上述查询层面的方案才是最优解。

内容的提问来源于stack exchange,提问作者dev1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:07:39