让一对一关系懒惰 [英] Making a OneToOne-relation lazy
问题描述
OneToMany
和 ManyToMany
关系都是懒惰的,所以这不是问题。在检查正在执行的实际SQL时,我注意到查询中有超过80个连接。 进一步检查问题,我注意到问题是由 OneToOne
和 ManyToOne
实体类之间的关系。所以,我想,我只是让他们偷懒,这应该可以解决问题。但注释 @OneToOne(fetch = FetchType.LAZY)
或 @ManyToOne(fetch = FetchType.LAZY)
doesn' t似乎工作。要么我得到一个异常,或者他们实际上并没有被一个代理对象所取代,因此是懒惰的。
任何想法如何让这个工作起作用?请注意,我没有使用 persistence.xml
来定义关系或配置细节,所有事情都是在java代码中完成的。
无约束(可空)的一对一关联是唯一不能在没有字节码检测的情况下进行代理的关联。原因是拥有者实体必须知道关联属性是否应该包含一个代理对象或NULL,并且它不能确定通过查看其基表的列是由于一对一地通过共享PK映射的,所以它无论如何,必须热切地提取代理,使代理毫无意义。以下是更详细的解释。
用一对多替换一对一的方式几乎不是一个好主意。您可以将其替换为多对一的唯一身份证,但还有其他(可能更好)选项。
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:
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.
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.
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屋!