Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA急切获取未加入_Java_Hibernate_Jpa_Join - Fatal编程技术网

Java JPA急切获取未加入

Java JPA急切获取未加入,java,hibernate,jpa,join,Java,Hibernate,Jpa,Join,JPA的fetch策略究竟控制着什么?我看不出渴望和懒惰有什么区别。在这两种情况下,JPA/Hibernate不会自动加入多对一关系 示例:此人只有一个地址。一个地址可以属于许多人。JPA注释实体类如下所示: @Entity public class Person { @Id public Integer id; public String name; @ManyToOne(fetch=FetchType.LAZY or EAGER) public A

JPA的fetch策略究竟控制着什么?我看不出渴望和懒惰有什么区别。在这两种情况下,JPA/Hibernate不会自动加入多对一关系

示例:此人只有一个地址。一个地址可以属于许多人。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;
}
如果我使用JPA查询:

select p from Person p where ...
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
这对于大型结果集非常不利。如果有1000人,它将生成1001个查询(1个来自Person,1000个不同于Address)。我知道这一点,因为我正在查看MySQL的查询日志。我的理解是,将address的fetch类型设置为eager将导致JPA/Hibernate使用连接自动查询。但是,不管获取类型如何,它仍然会为关系生成不同的查询

只有当我明确告诉它加入时,它才会真正加入:

select p, a from Person p left join p.address a where ...
我是不是遗漏了什么?现在,我必须手工编写每个查询的代码,以便它能够连接多对一关系。我在MySQL中使用Hibernate的JPA实现


Edit:看来(参见Hibernate常见问题解答和)FetchType不会影响JPA查询。所以在我的例子中,我明确地告诉它加入。

我想到了两件事

首先,你确定你的地址是manytone吗?这意味着多个人将拥有相同的地址。如果为其中一个进行了编辑,则将为所有这些对象进行编辑。这是你的意图吗?99%的时间地址是“私人”的(即它们只属于一个人)

第二,你对个人实体还有其他渴望的关系吗?如果我没记错的话,Hibernate只能处理实体上的一个急切关系,但这可能是过时的信息


我之所以这么说,是因为从我所处的位置来看,您对这应该如何工作的理解基本上是正确的。

fetchType属性控制在获取主实体时是否立即获取带注释的字段。它不一定规定fetch语句的构造方式,实际的sql实现取决于您使用的toplink/hibernate等提供程序

如果设置
fetchType=EAGER
,这意味着注释字段与实体中的其他字段同时填充其值。因此,如果打开entitymanager检索person对象,然后关闭entitymanager,则随后执行person.address不会导致引发延迟加载异常

如果设置
fetchType=LAZY
,则该字段仅在访问时填充。如果您已在之前关闭entitymanager,则如果执行person.address,将引发延迟加载异常。要加载字段,需要使用em.merge()将实体放回EntityRangers上下文中,然后进行字段访问,然后关闭entitymanager

在构造包含客户订单集合的客户类时,可能需要延迟加载。如果您在想要获取客户列表时检索了客户的每个订单,那么当您只查找客户名称和联系方式时,这可能是一项昂贵的数据库操作。最好将数据库访问权留到以后

对于问题的第二部分-如何让hibernate生成优化的SQL

Hibernate应该允许您提供有关如何构造最有效查询的提示,但我怀疑您的表构造有问题。表中是否建立了关系?Hibernate可能认为一个简单的查询比连接更快,尤其是在缺少索引等的情况下。

“mxc”是正确的
fetchType
只指定了何时应解析关系

要通过使用外部联接优化即时加载,必须添加

@Fetch(FetchMode.JOIN)

到你的领域去。这是一个特定于hibernate的注释。

如果使用EclipseLink而不是hibernate,则可以通过“查询提示”优化查询。请参阅EclipseWiki中的这篇文章:

有一章是关于“联合阅读”的。

尝试一下:

select p from Person p left join FETCH p.address a where...

对于我来说,它与JPA2/EclipseLink的工作原理类似,但这一特性似乎存在于:

我正好遇到了这个问题,但Person类有一个嵌入的key类。 我自己的解决方案是将它们加入查询并删除

@Fetch(FetchMode.JOIN)

我的嵌入式id类:

@Embeddable
public class MessageRecipientId implements Serializable {

    @ManyToOne(targetEntity = Message.class, fetch = FetchType.LAZY)
    @JoinColumn(name="messageId")
    private Message message;
    private String governmentId;

    public MessageRecipientId() {
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public String getGovernmentId() {
        return governmentId;
    }

    public void setGovernmentId(String governmentId) {
        this.governmentId = governmentId;
    }

    public MessageRecipientId(Message message, GovernmentId governmentId) {
        this.message = message;
        this.governmentId = governmentId.getValue();
    }

}

JPA没有提供任何关于将注释映射到选择获取策略的规范。通常,相关实体可以通过下面给出的任何一种方式获取

  • SELECT=>一个根实体查询+一个相关映射实体/每个根实体集合查询=(n+1)查询
  • SUBSELECT=>一个根实体查询+第二个相关映射实体查询/第一个查询中检索到的所有根实体集合=2个查询
  • JOIN=>一个查询来获取根实体及其所有映射实体/集合=1个查询
因此,
SELECT
JOIN
是两个极端,
SUBSELECT
介于两者之间。人们可以根据自己的领域模型选择合适的策略

默认情况下,JPA/EclipseLink和Hibernate都使用
SELECT
。这可以通过使用以下命令来覆盖:

@Fetch(FetchMode.JOIN) 
@Fetch(FetchMode.SUBSELECT)
冬眠。它还允许使用
@Fetch(FetchMode.SELECT)
显式设置
选择
模式,可以使用批大小进行调整,例如
@BatchSize(size=10)

EclipseLink中的相应注释为:

@JoinFetch
@BatchFetch

要加入,您可以做多种事情(使用eclipselink)

  • 在jpql中,您可以执行左连接获取

  • 在命名查询中,可以指定查询提示

  • 在TypedQuery中,您可以说

    query.setHint(“eclipselink.join-fetch”,“e.proje