为什么这会导致非延迟提取和N + 1选择语句?

时间:2014-07-27 15:01:14

标签: java hibernate lazy-loading

我希望只获得一个SQL查询,但我遇到了N + 1选择陷阱。我真的不明白为什么。这是问题的详细信息:

我有一个实体" PlayerRef":

@Entity
@Table(name = "player_ref")
public class PlayerRef {

  //constructor etc...

  @OptimisticLock(excluded = true)
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "playerRef")
  public Set<Player> getPlayers() {
    return players;
  }

}

一个班级球员:

@Entity
@Table(name = "player")
public class Player {

  //constructor etc...

  @OptimisticLock(excluded = true)
  @ManyToOne(optional = true, fetch = FetchType.LAZY)
    @JoinTable(name="cr_player_ref_player", 
      joinColumns = {
        @JoinColumn(name="player_id", unique = true)           
      }
      ,inverseJoinColumns = {
        @JoinColumn(name="player_ref_id")
      }     
    )
  public PlayerRef getPlayerRef() {
    return this.playerRef;
  }
}

现在,在我的程序中,我使用以下HQL查询来获取所有playerRef实体:

Query playerRefQ = session.createQuery("select playerRef from PlayerRef playerRef ")
  .setReadOnly(true); 
playerRefQ.setParameter("sport", sport);
@SuppressWarnings("unchecked")
List<PlayerRef> allPlayerRefs = playerRefQ.list();

这导致N + 1 Select语句:

1)

select
    playerref0_.id as id1_21_,
    playerref0_.... 
from
    player_ref playerref0_

N次)

select
    players0_.player_ref_id as player_r1_21_0_,
    players0_.player_id as player_i2_34_0_,
    player1_.id as id1_19_1_,
    player1_....,
    player1_1_.player_ref_id as player_r1_34_1_,
    ... 
from
    cr_player_ref_player players0_ 
inner join
    player player1_ 
        on players0_.player_id=player1_.id 
left outer join
    cr_player_ref_player player1_1_ 
        on player1_.id=player1_1_.player_id 
where
    players0_.player_ref_id=?

这是非常意外的,因为我认为该集合是延迟加载的,每个playerRef的玩家集应该是一个休眠代理。

任何人都知道如何才能加载playerRef实体而不加载相关的玩家?对于我的用例,我需要所有的playerRef,但不需要相关的玩家。

1 个答案:

答案 0 :(得分:2)

这里的问题来自于您的基础数据库结构实际上是many-to-many。有一个配对表cr_player_ref_player,这意味着,

  • 一个Player可以有多个PlayerRef
  • 一个PlayerRef可以有多个Player

请参阅Hibernate – Many-to-Many example

因为而不是:

public PlayerRef getPlayerRef() {
    return this.playerRef;
}

应该有:

public Set<PlayerRef> getPlayerRefs() {
    return playerRef;
}

Hibernate的混淆来自:@OneToMany(fetch = FetchType.LAZY, mappedBy = "playerRef"),主要是在"playerRef"下找到映射...而不是预期的many-to-one更复杂部分表达many-to-many。这就是为什么我们可以看到这些奇怪的N + 1 ...