我希望只获得一个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,但不需要相关的玩家。
答案 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 ...