标准渴望fetch-joined集合以避免n + 1选择

Cam*_*lva 12 java hibernate hibernate-criteria

假设Item和Bid是实体:Item有很多Bids.它们以典型的父/子关系映射到Hibernate中:

<class name="Item" table="ITEM">
  ...
  <set name="bids" inverse="true">
    <key column="ITEM_ID"/>
    <one-to-many class="Bid"/>
  </set>
</class>
Run Code Online (Sandbox Code Playgroud)

在执行此查询后尝试访问每个项目的出价时,如何避免n + 1选择?

List<Item> items = session.createCriteria(Item.class)
                        .createAlias("bids", "b").
                        .add(Restrictions.gt("b.amount", 100)).
                        .list();
Run Code Online (Sandbox Code Playgroud)

注意我需要一个热切的提取出价,但对集合有进一步的限制(b.amount> 100)

我尝试了下面的失败:

List<Item> items = session.createCriteria(Item.class)
                        .setFetchMode("bids", FetchMode.JOIN).
                        .createAlias("bids", "b").
                        .add(Restrictions.gt("b.amount", 100)).
                        .list();                        

List<Item> items = session.createCriteria(Item.class)
                        .createCriteria("bids")
                        .add(Restrictions.gt("amount", 100)).
                        .list();                        
Run Code Online (Sandbox Code Playgroud)

Yog*_*ngh 10

此条件查询似乎正确:

  List<Item> items = session.createCriteria(Item.class)
                    .setFetchMode("bids", FetchMode.JOIN)
                    .createAlias("bids", "b")
                    .add(Restrictions.gt("b.amount", 100))
                    .list();
Run Code Online (Sandbox Code Playgroud)

FetchMode.JOIN意在解决n+1问题.你有没有定义一些 default_batch_fetch_size| batch-size映射或配置中的任何位置,这是反向影响?

如果没有,你可以尝试下面的HQL,看看这解决了你的问题吗?

 Query query = 
      session.createQuery("from Item it left join it.bids b where b.amount=:bids");
 query.setParamter(bids, 100);
 List<Item> items = query.list();
Run Code Online (Sandbox Code Playgroud)


Cam*_*lva 6

这是为什么在fetch-joined集合上添加限制导致集合未初始化的原因(请注意,没有限制的相同查询会产生对集合的急切获取):

"如果表A和B之间有1:n的关系,并且你向B添加一个限制并且想要急切地获取A和B,那么问题就是当你想从A导航到B时会发生什么.你应该只看到B中符合限制的数据,或者你应该看到所有与A相关的B?" 在这里看到更多......

但是,使用HQL而不是条件,部分获取出价集合

List<Item> items = session.createQuery(
          "from Item i left join fetch i.bids b where b.amount > :amount")
          .setParameter("amount", 100)
          .list();
Run Code Online (Sandbox Code Playgroud)

在我看来这是不一致的,但它是如何工作的

顺便说一句,如果你需要的是父母及其所有孩子的名单,但只是父母的孩子都满足一定的限制,所以你可以使用这个

List<Item> items = session.createQuery(
          "from Item i left join fetch i.bids b " +
          "where not exists (from Bid b where b.item = i and b.amount <= :amount)")
          .setParameter("amount", 100)
          .list();
Run Code Online (Sandbox Code Playgroud)

这是一个相关的帖子:Hibernate查询没有返回完整对象.