JPA和Hibernate:一对一映射导致三个选择查询

时间:2014-08-17 21:27:27

标签: hibernate jpa

JPA 2.0 Hibernate 4.3.5

您好,

以下是我的OneToOne映射(示例代码假设1个客户只能有1个订单)

class Customer {
    private Order order;
    @OneToOne(mappedBy="customer", fetch=FetchType.LAZY)
    public Order getOrder() { return order; }
    public void setOrder(Order order) { this.order = order ; }
}

class Order {
    private Customer customer;
    @OneToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="cust_id")
    public Customer getCustomer() { return customer; }
    public void setCustomer(Customer customer) { this.customer = customer; }
}

//Calling code
Order order = em.find(Order.class, 4);    // Line 1
System.out.println(order.getCustomer());  // Line 2
</code>

上面的调用代码实际上产生了3个选择语句,即

第1行导致

   select * from order where id = ?      #1

第2行导致以下两个陈述

   select * from customer where id = ?   #2
   select * from order where cust_id = ? #3

我的问题: 鉴于两端都启用了LAZY提取,是不是只有两个查询(即#1和#2)?

谢谢, 勒凯什

4 个答案:

答案 0 :(得分:3)

您已将这两种关系定义为LAZY。

加载订单时,不会加载Customer属性,因为它是LAZY。只有在访问LAZY属性或将其定义为急切加载时才会加载它。

默认情况下,每个映射都以一个(OneToOne或ManyToOne)结束,但您将其设置为LAZY。

尝试将您的关系定义为EAGER:

@OneToOne(fetch=FetchType.EAGER) // or just @OneToOne
@JoinColumn(name="cust_id")
public Customer getCustomer() { return customer; }

顺便说一句,您的客户只能订购一份订单? O.o

答案 1 :(得分:2)

我认为问题出在一对一的关系上,你不能延迟加载 看看https://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one。 由于您首先加载订单对象,因此它将发出接下来的两个查询以加载客户,然后发出一对一的关系。 简单地避免此问题的一种可能性是将客户对象定义为可选

  

类客户{           私人订单;           @OneToOne(mappedBy =“customer”,fetch = FetchType.LAZY, optional = true )           public order getOrder(){return order; }           public void setOrder(Order order){this.order = order; }       }

答案 2 :(得分:2)

由于表格的布局方式,它永远不会是两个查询。

将fetchMode设置为LAZY指示hibernate创建代理。这样的代理包含要加载的对象的类型及其密钥(id),以便hibernate可以在以后使用任何方法时加载它(某些例外)。

因此,当hibernate从db加载订单时,它可以轻松构建订单对象和客户代理:它具有订单表中的所有信息,因为cust_id在该表中。 [这是你的主叫代码的第一行发生的事情]

这不是加载客户对象的情况:为了创建代理对象的订单,hibernate无论如何都必须查询订单表,因为该代理的密钥是在该表中定义的。这就是为什么你总是看到第三个查询。 [这是在调用代码的第二行上发生的事情:在代理上调用toString()方法并加载实际数据。]

在一对一关联的反面将fetchMode设置为LAZY因此对查询条款几乎没有影响。一对多的情况会有所不同。

根据您真正需要的内容,您可以提出异国情调的映射 - 例如将连接中的一对一关联转换为加入或加入几个字段 - 以帮助提高性能。

答案 3 :(得分:1)

如果您只想在一个查询中解决问题,则应制作“n + 1查询问题”的变体,由JOIN FETCH解决。

FETCH JOINS是实现和解决(N Time M + 1)查询问题的最简单方法。

SELECT item FROM ItemRecord
 JOIN FETCH item.costs,
 JOIN FETCH item.notes,
 JOIN FETCH item.stats;

我建议你article