想象一下关系数据库中的2个表,例如Person和Billing。这些实体之间定义了一个(非强制性的)OneToOne关联,并且它们共享Person主键(即,PERSON_ID在Person和Billing中都定义,并且在后者中是外键)。
通过命名查询对Person进行选择时,例如:
from Person p where p.id = :id
Hibernate / JPA生成两个选择查询,一个在“人”表上,另一个在“帐单”表上。
鉴于查询仅返回一个结果,上述示例非常简单,不会引起任何性能问题。现在,假设与其他实体(都共享主键)Person具有nOneToOne关系(全部为非强制性Person)。
Person
n
如果我错了,请更正我,但是select在Person上运行查询并返回r行(n+1)*r,即使关联是 lazy ,也会导致Hibernate生成选择。
select
r
(n+1)*r
有没有针对这种潜在性能灾难的解决方法(除了根本不使用共享主键之外)?谢谢您的所有想法。
想象一下关系数据库中的2个表,例如Person和Billing。这些实体之间定义了一个(非强制性的)OneToOne关联,
从概念上讲,默认情况下对于非强制性的OneToOne不可能进行延迟获取,Hibernate必须访问数据库才能知道关联是否null存在。来自这个旧的Wiki页面的更多详细信息:
null
关于延迟加载(一对一)的一些说明 […] 现在考虑我们的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对象可能有关联C (constrained="false"),也可能没有关联()。 没有getCee()特定的B时候应该返回什么 C?空值。但是请记住,Hibernate必须在设置时立即设置“ cee”的正确值B (因为它不知道何时有人会呼叫getCee())。代理服务器在这里没有帮助,因为代理服务器本身已经存在于非null对象中。 简历: 如果B- > C映射是必需的(constrained=true),则Hibernate将对C使用代理,从而导致延迟初始化。但是,如果允许B不带C,则Hibernate只需在加载B时检查C的存在。但是SELECT来检查存在性的SELECT效率低下,因为同一SELECT可能不仅检查存在性,而且还加载了整个对象。因此,懒惰的负载消失了。
关于延迟加载(一对一)的一些说明
[…]
现在考虑我们的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。
getCee()
cee
C
one-to-one
但是现在想象一下您的B对象可能有关联C (constrained="false"),也可能没有关联()。 没有getCee()特定的B时候应该返回什么 C?空值。但是请记住,Hibernate必须在设置时立即设置“ cee”的正确值B (因为它不知道何时有人会呼叫getCee())。代理服务器在这里没有帮助,因为代理服务器本身已经存在于非null对象中。
B
constrained="false"
简历: 如果B- > C映射是必需的(constrained=true),则Hibernate将对C使用代理,从而导致延迟初始化。但是,如果允许B不带C,则Hibernate只需在加载B时检查C的存在。但是SELECT来检查存在性的SELECT效率低下,因为同一SELECT可能不仅检查存在性,而且还加载了整个对象。因此,懒惰的负载消失了。
constrained=true
因此,不可能…默认情况下。
问题不是共享主键,有或没有共享主键,您都会明白的,问题是 可 为 空的 OneToOne。
第一种选择 :使用字节码检测(请参阅下面的文档参考)和 无代理 获取:
@OneToOne( fetch = FetchType.LAZY ) @org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
第二种选择 :使用假货ManyToOne(fetch=FetchType.LAZY)。那可能是最简单的解决方案(据我所知,是推荐的解决方案)。但是我没有使用共享PK对此进行测试。
ManyToOne(fetch=FetchType.LAZY)
第三种选择 :急于使用加载结算信息join fetch。
join fetch