Ste*_*Kuo 106 java hibernate jpa join
JPA的获取策略到底控制了什么?我无法发现渴望和懒惰之间的任何区别.在这两种情况下,JPA/Hibernate都不会自动加入多对一关系.
示例:Person有一个地址.地址可以属于很多人.JPA带注释的实体类看起来像:
@Entity
public class Person {
@Id
public Integer id;
public String name;
@ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
@Entity
public class Address {
@Id
public Integer id;
public String name;
}
Run Code Online (Sandbox Code Playgroud)
如果我使用JPA查询:
select p from Person p where ...
Run Code Online (Sandbox Code Playgroud)
JPA/Hibernate生成一个SQL查询以从Person表中进行选择,然后为每个人选择一个不同的地址查询:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
Run Code Online (Sandbox Code Playgroud)
这对于大型结果集非常糟糕.如果有1000个人,则会生成1001个查询(1个来自Person,1000个来自地址).我知道这是因为我正在查看MySQL的查询日志.我的理解是,将地址的提取类型设置为eager会导致JPA/Hibernate自动使用连接进行查询.但是,无论获取类型如何,它仍会为关系生成不同的查询.
只有当我明确告诉它加入时它才真正加入:
select p, a from Person p left join p.address a where ...
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么吗?我现在必须手动编写每个查询的代码,以便它离开加入多对一关系.我正在使用Hibernate的JPA实现与MySQL.
编辑:它出现(请参阅此处和此处的 Hibernate常见问题解答),FetchType
不会影响JPA查询.所以在我的情况下,我明确告诉它加入.
Yad*_*adu 92
JPA没有提供关于将注释映射到选择获取策略的任何规范.通常,可以以下面给出的任何一种方式获取相关实体
所以SELECT
,JOIN
它们是两个极端SUBSELECT
,介于两者之间.可以根据她/他的领域模型选择合适的策略.
默认情况下SELECT
,JPA/EclipseLink和Hibernate都使用它们.这可以通过使用来覆盖:
@Fetch(FetchMode.JOIN)
@Fetch(FetchMode.SUBSELECT)
Run Code Online (Sandbox Code Playgroud)
在Hibernate中.它还允许SELECT
显式设置模式@Fetch(FetchMode.SELECT)
,可以使用批量大小调整,例如@BatchSize(size=10)
.
EclipseLink中的相应注释是:
@JoinFetch
@BatchFetch
Run Code Online (Sandbox Code Playgroud)
rud*_*son 44
"mxc"是对的.fetchType
只是指定何时应该解决关系.
要通过使用外部联接来优化预先加载,您必须添加
@Fetch(FetchMode.JOIN)
Run Code Online (Sandbox Code Playgroud)
到你的领域.这是一个特定于hibernate的注释.
mxc*_*mxc 37
fetchType属性控制在获取主实体时是否立即获取带注释的字段.它不一定决定如何构造fetch语句,实际的sql实现依赖于你使用toplink/hibernate等的提供者.
如果设置,fetchType=EAGER
则表示带注释的字段与实体中的其他字段同时填充其值.因此,如果您打开一个实体管理器来检索您的人物对象然后关闭实体管理器,则随后执行person.address将不会导致抛出延迟加载异常.
如果设置fetchType=LAZY
该字段仅在访问时填充.如果您已关闭实体管理器,那么如果您执行person.address,则会抛出延迟加载异常.要加载字段,您需要使用em.merge()将实体放回到实体管理器上下文中,然后执行字段访问,然后关闭实体管理器.
在构建具有客户订单集合的客户类时,您可能需要延迟加载.如果您在想要获取客户列表时检索了客户的每个订单,那么当您只查找客户名称和联系详细信息时,这可能是一项昂贵的数据库操作.最好将数据库访问留到以后.
对于问题的第二部分 - 如何让hibernate生成优化的SQL?
Hibernate应该允许您提供有关如何构建最有效查询的提示,但我怀疑您的表构造有问题.表中是否建立了关系?Hibernate可能已经决定简单的查询比连接更快,特别是如果缺少索引等.
sin*_*pop 18
试试:
select p from Person p left join FETCH p.address a where...
Run Code Online (Sandbox Code Playgroud)
它对我来说与JPA2/EclipseLink类似,但似乎JPA1中也存在此功能:
如果您使用EclipseLink而不是Hibernate,则可以通过"查询提示"优化查询.请参阅Eclipse Wiki中的这篇文章:EclipseLink/Examples/JPA/QueryOptimization.
有一章关于"加入阅读".
我想到了两件事。
首先,您确定您的地址是指 ManyToOne 吗?这意味着多个人将拥有相同的地址。如果针对其中之一进行了编辑,那么也会针对所有这些进行编辑。这是你的意图吗?99% 的时间地址都是“私有的”(从某种意义上说,它们只属于一个人)。
其次,您在 Person 实体上还有其他渴望的关系吗?如果我没记错的话,Hibernate 只能处理实体上的一种渴望关系,但这可能是过时的信息。
我这么说是因为从我现在的角度来看,你对它应该如何运作的理解基本上是正确的。
归档时间: |
|
查看次数: |
116263 次 |
最近记录: |