JPA和Hibernate:一对一映射导致三个select查询
JPA2.0 休眠4.3.5 嗨 下面是我的OneTONE映射,示例代码假设一个客户只能有一个订单JPA和Hibernate:一对一映射导致三个select查询,hibernate,jpa,Hibernate,Jpa,JPA2.0 休眠4.3.5 嗨 下面是我的OneTONE映射,示例代码假设一个客户只能有一个订单 class Customer { private Order order; @OneToOne(mappedBy="customer", fetch=FetchType.LAZY) public Order getOrder() { return order; } public void setOrder(Order order) { this.order = or
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条select语句,即
第1行引起
select * from order where id = ? #1
第2行有以下两条语句
select * from customer where id = ? #2
select * from order where cust_id = ? #3
我的问题:
如果两端都启用了延迟抓取,那么不应该只有两个查询,即1和2吗
谢谢,
Rakesh我认为问题在于一对一的关系,你不能有延迟加载,看看 由于您是在客户之前加载order对象,因此它将发出下两个查询以加载客户,然后是其一对一关系 简单地避免此问题的一种可能性是将customer对象定义为可选:
class Customer {
private Order order;
@OneToOne(mappedBy="customer", fetch=FetchType.LAZY,**optional=true**)
public Order getOrder() { return order; }
public void setOrder(Order order) { this.order = order ; }
}
您已将这两个关系定义为懒惰 加载订单时,不会加载Customer属性,因为它是惰性的。惰性属性只有在被访问或定义为急切加载时才会被加载 默认情况下,使用一个OneToOne或多个OneToOne完成的每个映射都会很受欢迎,但您将其设置为LAZY 尝试将您的关系定义为渴望:
@OneToOne(fetch=FetchType.EAGER) // or just @OneToOne
@JoinColumn(name="cust_id")
public Customer getCustomer() { return customer; }
顺便问一下,您的客户只能订购一份?O.O如果您只想在一个查询中解决问题,那么您应该创建一个n+1查询问题的变体,通过JOIN FETCH解决 fetchjoin是实现和解决N次M+1查询问题的最简单方法
SELECT item FROM ItemRecord
JOIN FETCH item.costs,
JOIN FETCH item.notes,
JOIN FETCH item.stats;
我建议您这样做。由于表的布局方式,永远不会有两个查询 将fetchMode设置为LAZY将指示hibernate创建代理。这样的代理包含要加载的对象的类型及其键id,以便hibernate可以在以后使用它的任何方法时加载该对象(某些异常情况下) 因此,当hibernate从db加载订单时,它可以轻松地构造订单对象和客户代理:它拥有订单表中的所有信息,因为cust_id位于该表中。[这是调用代码的第一行发生的情况] 加载customer对象的情况并非如此:为了创建代理对象的订单,hibernate无论如何都必须查询订单表,因为该代理的键是在该表中定义的。这就是为什么您总是看到第三个查询。[这是调用代码的第二行发生的情况:在代理上调用toString方法并加载实际数据。] 因此,在一对一关联的反面将fetchMode设置为LAZY实际上对查询条件没有影响。一对多的情况会有所不同
根据您的实际需要,您可以提出一些奇特的映射,例如使用联接反转一对一的关联,或者只加入几个字段,以帮助提高性能。您是否覆盖了Customer类的toString?否。不管怎么说,这有关系吗?是的,println调用了一个你可能弄糟的字符串方法。你解决了这个问题吗?如果是,你是怎么解决的?非常感谢兄弟!我缺少可选的=true参数您提供的链接不再可用