Hibernate别名 - 仍然执行n + 1选择是否正常?

时间:2011-09-12 14:02:26

标签: java hibernate

我有一个非常具体的2部分问题,我真的希望以前没有被问过:)

首先是上下文

我有一些Hibernate bean,它们之间存在惰性关联,例如:

@Entity
public class SalesData {

   @ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
   @JoinColumn(nullable = false)
   public Product getProduct() {
     return product;
   }

}

然后是:

@Entity
public class Product {

  @OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  public Set<SoundRecording> getSoundRecordings() {
    return soundRecordings;
  }

}

最后:

@Entity public class SoundRecording {
}

现在,如果我创建一个Criteria查询,我在其中为SalesData to Product关系添加别名,然后为Product to SoundRecording添加别名,如下所示:

Criteria criteria = session.createCriteria(SalesData.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.createAlias("product", "p");
criteria.createAlias("p.soundRecordings", "s");

我可以在Hibernate的日志中看到他生成SQL,如:

select ... from SalesData this_ 
inner join Product p1_ on this_.product_id=p1_.id 
    inner join SoundRecording s5_ on p1_.id=s5_.product_id 
        where ...

当我调用criteria.list()时,这正是我想要的。但是,如果我这样做:

salesDatas.getProduct().getSoundRecordings(0);

我可以在日志中看到Hibernate已经创建了另一个特定的SQL select查询来检索这种关联:

select ... from SoundRecording soundrecor0_ where soundrecor0_.product_id=?

我的问题是:

这是正常的吗?我的目标是一次性加载(使用一个SQL查询)我需要的所有内容,以便我可以避免这些n + 1选择。我认为使用别名是一种方法,特别是因为我可以清楚地看到他在表之间生成内部联接。如果我使用explictit fetchMode(Join),那么hibernate将不会发出所有额外的选择,它将满足初始选择与许多(outter)连接。那么为什么对别名生成的连接不一样呢?

1 个答案:

答案 0 :(得分:2)

别名或子标准用于创建连接。此联接可能有两个目标:

  1. 通过对已连接实体添加限制来限制返回值集合
  2. 选择已加入实体的字段
  3. 如果你想要1并且不想要2,则不需要提取,因此你不应该调用setFetchMode())。如果你想要2,那么就需要提取。

    示例:您可能希望搜索当前月份中订单的所有产品,但不会对订单字段中的所有产品感兴趣。在这种情况下,不需要获取产品订单,如果某些产品在一个月内有数百或数千个订单,则会非常昂贵。