Ign*_*aca 5 java orm hibernate jpa
我的问题是,对于每个空关系,Hibernate急切加载OneToOne关联会执行+1 select.
实体示例:
@Entity
class SideBlue {
@Column(nullable = false)
private Integer timestamp;
@OneToOne(optional=true)
@JoinColumn(name="timestamp", referenceColumn="timestamp", insertable = false, updatable = false)
SideRed redSide;
}
@Entity
class SideRed {
@Column(nullable = false)
private Integer timestamp;
}
Run Code Online (Sandbox Code Playgroud)
(这是遗留数据库模式,因此不允许进行数据库修改)
查询示例:
CriteriaBuilder builder... CriteriaQuery query...
Root<SideBlue> root = query.from(SideBlue.class);
root.fetch(SideBlue_.sideRed, JoinType.LEFT);
entityManager().createQuery(query).getResultList();
Run Code Online (Sandbox Code Playgroud)
结果:如果所有蓝色边实体都有一个红色边,一切都正常,所以hibernate只对数据库执行一个查询,无论哪个实体都将被检索.
但是,如果蓝方实体没有关联的红色实体,那么hibernate会再次尝试找到另一方.Hibernate sql注释为每个null redSide属性说'/*load RedSide*/select ...'.
如何跳过第二次选择?
当延迟不是非常低时,出现实际问题.如果我尝试选择1百万行,并且1/3具有空的"红色边",则添加的总延迟是一个真正的问题.
编辑:
这是查询的调试日志
10:04:32.812 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
10:04:32.815 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269721], EntityKey[SideRed#3620564]
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result set row: 1
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269776], null
Run Code Online (Sandbox Code Playgroud)
第一行包含蓝色和红色边,但第二行仅包含蓝色边.所以hibernate必须知道相关的红色方面不存在.但是,在处理完所有结果行之后......
10:04:33.083 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [BlueSide#1269721]
10:04:33.084 [main] DEBUG org.hibernate.loader.Loader - Loading entity: [RedSide#component[timestamp]{timestamp=1338937390}]
10:04:33.084 [main] DEBUG org.hibernate.SQL - /* load RedSide */ select ...
! Nothing really loaded because the previous SQL return empty result set, again !
10:04:33.211 [main] DEBUG org.hibernate.loader.Loader - Done entity load
Run Code Online (Sandbox Code Playgroud)
好吧,当您查询 SideBlue 时,您试图不加载 SideRed。我认为这是一个与 Hibernate 的“限制”相关的延迟加载问题(来自https://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one?_sscc=t):
Run Code Online (Sandbox Code Playgroud)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() 是您的类的方法,Hibernate 无法控制它。Hibernate 不知道什么时候有人会调用 getCee()。这意味着 Hibernate 在从数据库加载 B 时必须将适当的值放入“cee”属性中。
如果为C启用了代理,Hibernate可以放置一个尚未加载的C代理对象,但当有人使用它时会加载它。这为一对一提供了延迟加载。
但现在想象一下您的 B 对象可能有也可能没有关联的 C (constrained="false")。当特定 B 没有 C 时 getCee() 应该返回什么?无效的。但请记住,Hibernate 必须在设置 B 时设置正确的“cee”值(因为它不知道何时有人会调用 getCee())。代理在这里没有帮助,因为代理本身已经在非空对象中。
因此,简历:如果您的 B->C 映射是强制性的(constrained=true),Hibernate 将使用 C 的代理,从而导致延迟初始化。但是如果你允许 B 没有 C,Hibernate 只需在加载 B 时检查 C 是否存在。但是检查存在的 SELECT 效率很低,因为相同的 SELECT 可能不仅检查存在,而且加载整个对象。所以延迟加载就消失了。
| 归档时间: |
|
| 查看次数: |
4622 次 |
| 最近记录: |