当前位置: 首页 > 面试题库 >

具有共享主键的OneToOne关系生成n + 1个选择;任何解决方法?

巫墨一
2023-03-14
问题内容

想象一下关系数据库中的2个表,例如Person和Billing。这些实体之间定义了一个(非强制性的)OneToOne关联,并且它们共享Person主键(即,PERSON_ID在Person和Billing中都定义,并且在后者中是外键)。

通过命名查询对Person进行选择时,例如:

from Person p where p.id = :id

Hibernate / JPA生成两个选择查询,一个在“人”表上,另一个在“帐单”表上。

鉴于查询仅返回一个结果,上述示例非常简单,不会引起任何性能问题。现在,假设与其他实体(都共享主键)Person具有nOneToOne关系(全部为非强制性Person)。

如果我错了,请更正我,但是select在Person上运行查询并返回r(n+1)*r,即使关联是 lazy
,也会导致Hibernate生成选择。

有没有针对这种潜在性能灾难的解决方法(除了根本不使用共享主键之外)?谢谢您的所有想法。


问题答案:

想象一下关系数据库中的2个表,例如Person和Billing。这些实体之间定义了一个(非强制性的)OneToOne关联,

从概念上讲,默认情况下对于非强制性的OneToOne不可能进行延迟获取,Hibernate必须访问数据库才能知道关联是否null存在。来自这个旧的Wiki页面的更多详细信息:

关于延迟加载(一对一)的一些说明

[…]

现在考虑我们的B类与C具有一对一关联

class B {
    private C cee;

    public C getCee() {
        return cee;
    }

    public void setCee(C cee) {
        this.cee = cee;
    }
}

class C {
    // Not important really
}

加载B之后,您可以调用 getCee()获得C。但是,看,这
getCee()是YOUR类的方法,并且Hibernate无法对其进行控制。Hibernate不知道何时有人要打电话getCee()。这意味着Hibernate
cee在从数据库加载B时必须将一个适当的值添加到“ ”属性中。如果启用了proxy
C,则Hibernate可以放置一个C代理对象,该对象尚未加载,但在有人使用它时将被加载。这会导致的延迟加载 one-to-one

但是现在想象一下您的B对象可能有关联Cconstrained="false"),也可能没有关联()。
没有getCee()特定的B时候应该返回什么 C?空值。但是请记住,Hibernate必须在设置时立即设置“ cee”的正确值B
(因为它不知道何时有人会呼叫getCee())。代理服务器在这里没有帮助,因为代理服务器本身已经存在于非null对象中。

简历: 如果B- >
C映射是必需的(constrained=true),则Hibernate将对C使用代理,从而导致延迟初始化。但是,如果允许B不带C,则Hibernate只需在加载B时检查C的存在。但是SELECT来检查存在性的SELECT效率低下,因为同一SELECT可能不仅检查存在性,而且还加载了整个对象。因此,懒惰的负载消失了

因此,不可能…默认情况下。

有没有针对这种潜在性能灾难的解决方法(除了根本不使用共享主键之外)?谢谢您的所有想法。

问题不是共享主键,有或没有共享主键,您都会明白的,问题是 空的 OneToOne。

第一种选择 :使用字节码检测(请参阅下面的文档参考)和 无代理 获取:

@OneToOne( fetch = FetchType.LAZY )
@org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)

第二种选择
:使用假货ManyToOne(fetch=FetchType.LAZY)。那可能是最简单的解决方案(据我所知,是推荐的解决方案)。但是我没有使用共享PK对此进行测试。

第三种选择 :急于使用加载结算信息join fetch

参考文献

  • hibernate参考指南
    • 19.1.3。单端关联代理
    • 19.1.7。使用懒惰的属性获取
  • 旧的Hibernate常见问题解答
    • 如何将一对一关系设置为惰性关系?
  • hibernateWiki
    • 关于延迟加载(一对一)的一些说明


 类似资料:
  • 问题内容: 我正在尝试使用JPA / Hibernate设置以下表: 可能有很多用户,每个用户最多只能有一个验证码,也可能没有。 这是我的课程: 我创建一个用户,然后尝试使用以下代码添加验证代码: 当我尝试运行它时,我收到org.hibernate.PersistentObjectException:分离的实体传递给持久化:用户 我还尝试在Validation类中使用以下代码: 当我创建验证码时,

  • 问题内容: 我很难理解如何避免在jpa或hibernate状态下进行n + 1选择。 从我阅读的内容来看,有一个“ left join fetch”,但是我不确定它是否仍然适用于多个列表(oneToMany)。 有人可以给我解释一下,还是给我一个带有清晰完整说明的链接? 很抱歉,如果这是一个菜鸟问题,但我找不到关于此问题的真正清晰的文章或文档。 谢谢 问题答案: 除了联接之外,您还可以使用子选择。

  • 问题内容: 我的任务是为可大规模扩展的分布式共享内存(DSM)应用程序构建原型。原型仅用作概念验证,但我想通过选择稍后在实际解决方案中使用的组件来最有效地利用我的时间。 该解决方案的目的是获取来自外部源的数据输入,将其搅动并使结果可用于许多前端。这些“前端”将仅从缓存中获取数据并提供服务,而无需额外的处理。该数据的前端命中量实际上可以是每秒数百万。 数据本身非常不稳定。它可以(并且确实)快速变化。

  • 我在读下面的文章: 然而,student实体是用mappedBy注释的,我知道任何用mappedBy注释的实体都是相反的一面。谁能解释一下这个吗? 2-哪个ID是外键?@PrimaryKeyJoinColumn在Address实体中使用,这意味着地址Id是主键和外键吗?在下面的文章中,它们有相同的示例,但它是单向的: http://websystique.com/hibernate/hiberna

  • 我在MySQL中有下表。 表1(身份证、名字、姓氏、电话号码) 表2(TID、电子邮件) 我在 Table1 中有 25000 行,而我的 Table2 包含 20000 行。我在表 2 中的 TID 是引用表 1 的主键 ID 的外键。如果姓氏为 NULL,则 Table2 中将不存在这些 ID。现在,我正在尝试仅针对具有姓氏的表合并这两个表。 我重新定义了表2的模式,如下所示。 Table2(

  • 我有两个类 TempResult 和 结果,它们之间需要多对一。临时收割有一个复合键。结果还需要 TempResult 的复合键中的所有属性(一个属性除外)作为其主键。 在TempResult中包含@ManyTone的情况下,如果在@JoinColumn中设置了insertable=false和Updateable=false,则表结构完全正常。但它不允许在TempResult表中创建新条目。如果