让一对一关系懒惰 [英] Making a OneToOne-relation lazy

查看:125
本文介绍了让一对一关系懒惰的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这个应用程序中,我们正在开发,我们注意到一个视图特别慢。我对该视图进行了剖析,并注意到有一个查询由hibernate执行,即使数据库中只有两个对象要获取,也需要10秒。所有 OneToMany ManyToMany 关系都是懒惰的,所以这不是问题。在检查正在执行的实际SQL时,我注意到查询中有超过80个连接。

进一步检查问题,我注意到问题是由 OneToOne ManyToOne 实体类之间的关系。所以,我想,我只是让他们偷懒,这应该可以解决问题。但注释 @OneToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY) doesn' t似乎工作。要么我得到一个异常,或者他们实际上并没有被一个代理对象所取代,因此是懒惰的。



任何想法如何让这个工作起作用?请注意,我没有使用 persistence.xml 来定义关系或配置细节,所有事情都是在java代码中完成的。

KLE 的回答进行一些说明:


    无约束(可空)的一对一关联是唯一不能在没有字节码检测的情况下进行代理的关联。原因是拥有者实体必须知道关联属性是否应该包含一个代理对象或NULL,并且它不能确定通过查看其基表的列是由于一对一地通过共享PK映射的,所以它无论如何,必须热切地提取代理,使代理毫无意义。以下是更详细的解释。


  1. 多对一的关联(显然,一对多关系)不会遇到这个问题。所有者实体可以轻松地检查自己的FK(并且在一对多,空集合代理最初创建并按需填充的情况下),因此该关联可以是懒惰的。

  2. 用一对多替换一对一的方式几乎不是一个好主意。您可以将其替换为多对一的唯一身份证,但还有其他(可能更好)选项。

  3. > Rob H。有一个有效的点,但是您可能无法根据您的模型实现它(例如,如果您的一对一关联 可以为空)。

    >

    现在,就原始问题而言:

    @ManyToOne(fetch = FetchType .LAZY)应该可以正常工作。你确定它在查询本身中没有被覆盖吗?可以在HQL中指定 join fetch 并且/或者通过Criteria API显式设置获取模式,这将优先于类注解。如果情况并非如此,并且仍然存在问题,请发布您的课程,查询以及生成的SQL,以便进行更加具体的对话。



    B) @OneToOne 更棘手。如果它绝对不能为空,请与Rob H.的建议一起使用,并指定它:

      @OneToOne(可选= false ,fetch = FetchType.LAZY)

    否则,如果您可以更改数据库(添加外键列到所有者表),这样做并将其映射为已加入:

      @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name =other_entity_fk)
    public OtherEntity getOther()

    和在OtherEntity中:

      @OneToOne(mappedBy =other)
    public OwnerEntity getOwner()

    如果您不能这样做(并且不能满足预先提取)字节码检测是您唯一的选择。然而,我必须同意 CPerkins ,如果您有 80 !!! 由于热切的OneToOne关联而加入,那么您遇到的问题就更大了: - ) p>

    In this application we are developing, we noticed that a view was particularly slow. I profiled the view and noticed that there was one query executed by hibernate which took 10 seconds even if there only were two object in the database to fetch. All OneToMany and ManyToMany relations were lazy so that wasn't the problem. When inspecting the actual SQL being executed, I noticed that there were over 80 joins in the query.

    Further inspecting the issue, I noticed that the problem was caused by the deep hierarchy of OneToOne and ManyToOne relations between entity classes. So, I thought, I'll just make them fetched lazy, that should solve the problem. But annotating either @OneToOne(fetch=FetchType.LAZY) or @ManyToOne(fetch=FetchType.LAZY) doesn't seem to work. Either I get an exception or then they are not actually replaced with a proxy object and thus being lazy.

    Any ideas how I'll get this to work? Note that I do not use the persistence.xml to define relations or configuration details, everything is done in java code.

    解决方案

    First off, some clarifications to KLE's answer:

    1. Unconstrained (nullable) one-to-one association is the only one that can not be proxied without bytecode instrumentation. The reason for this is that owner entity MUST know whether association property should contain a proxy object or NULL and it can't determine that by looking at its base table's columns due to one-to-one normally being mapped via shared PK, so it has to be eagerly fetched anyway making proxy pointless. Here's a more detailed explanation.

    2. many-to-one associations (and one-to-many, obviously) do not suffer from this issue. Owner entity can easily check its own FK (and in case of one-to-many, empty collection proxy is created initially and populated on demand), so the association can be lazy.

    3. Replacing one-to-one with one-to-many is pretty much never a good idea. You can replace it with unique many-to-one but there are other (possibly better) options.

    Rob H. has a valid point, however you may not be able to implement it depending on your model (e.g. if your one-to-one association is nullable).

    Now, as far as original question goes:

    A) @ManyToOne(fetch=FetchType.LAZY) should work just fine. Are you sure it's not being overwritten in the query itself? It's possible to specify join fetch in HQL and / or explicitly set fetch mode via Criteria API which would take precedence over class annotation. If that's not the case and you're still having problems, please post your classes, query and resulting SQL for more to-the-point conversation.

    B) @OneToOne is trickier. If it's definitely not nullable, go with Rob H.'s suggestion and specify it as such:

    @OneToOne(optional = false, fetch = FetchType.LAZY)
    

    Otherwise, if you can change your database (add a foreign key column to owner table), do so and map it as "joined":

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="other_entity_fk")
    public OtherEntity getOther()
    

    and in OtherEntity:

    @OneToOne(mappedBy = "other")
    public OwnerEntity getOwner()
    

    If you can't do that (and can't live with eager fetching) bytecode instrumentation is your only option. I have to agree with CPerkins, however - if you have 80!!! joins due to eager OneToOne associations, you've got bigger problems then this :-)

    这篇关于让一对一关系懒惰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆