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)?
谢谢, 勒凯什
答案 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。