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

oct*_*cty 7 java hibernate jpa

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

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

from Person p where p.id = :id
Run Code Online (Sandbox Code Playgroud)

Hibernate/JPA生成两个选择查询,一个在Person表上,另一个在Billing表上.

上面的示例非常简单,并且不会导致任何性能问题,因为查询只返回一个结果.现在,假设PersonnOneToOne关系(均非强制性)与其他实体(所有共享Person主键).

如果我错了,请纠正我,但是select在Person上运行查询,返回r行,将导致(n+1)*rHibernate生成选择,即使这些关联是懒惰的.

是否存在针对此潜在性能灾难的解决方法(除了根本不使用共享主键)?谢谢你的所有想法.

Pas*_*ent 8

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

对于非强制性OneToOne,默认情况下,懒惰提取在概念上是不可能的,Hibernate必须访问数据库才能知道关联是否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
}
Run Code Online (Sandbox Code Playgroud)

在加载B之后,你可以调用 getCee()获得C.但是看, getCee()是你的类的一种方法,而Hibernate无法控制它.Hibernate不知道有人什么时候打电话getCee().这意味着Hibernate必须cee在从数据库加载B时将适当的值放入" "属性中.如果启用了代理 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可能不仅仅检查存在,而是加载整个对象.懒惰的装载消失了.

所以,不可能......默认情况下.

是否存在针对此潜在性能灾难的解决方法(除了根本不使用共享主键)?谢谢你的所有想法.

问题不是共享主键,无论是否有共享主键,你都会得到它,问题是可以为空的 OneToOne.

第一个选项:使用字节码检测(参见下面的文档参考)和无代理提取:

@OneToOne( fetch = FetchType.LAZY )
@org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
Run Code Online (Sandbox Code Playgroud)

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

第三个选项:使用a预先加载结算join fetch.

相关问题

参考