我期望仅获得一个sql查询,但遇到N + 1选择陷阱。我真的不明白为什么。这是详细的问题:
我有一个实体“ PlayerRef”:
@Entity
@Table(name = "player_ref")
public class PlayerRef {
//constructor etc...
@OptimisticLock(excluded = true)
@LazyCollection(LazyCollectionOption.TRUE)
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "playerRefs")
public Set<Player> getPlayers() {
return players;
}
}
和一个班级球员:
@Entity
@Table(name = "player")
public class Player {
//constructor etc...
@OptimisticLock(excluded = true)
@LazyCollection(LazyCollectionOption.TRUE)
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="cr_player_ref_player",
joinColumns = {
@JoinColumn(name="player_id", unique = true)
}
,inverseJoinColumns = {
@JoinColumn(name="player_ref_id")
}
)
private Set<PlayerRef> getPlayerRefs() {
return this.playerRefs;
}
}
现在,在我的程序中,我使用以下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_0_,
...
from
player_ref playerref0_
N次)
select
players0_.player_ref_id as player_r2_21_0_,
players0_.player_id as player_i1_34_0_,
player1_.id as id1_19_1_,
...
from
cr_player_ref_player players0_
inner join
betdata.player player1_
on players0_.player_id=player1_.id
where
players0_.player_ref_id=?
(再次)这是非常出乎意料的,因为我认为该集合是延迟加载的,并且每个playerRef的播放器集都应该是一个休眠代理。
谁知道我真的只能加载playerRef实体而又不加载关联的玩家吗?对于我的用例,我需要所有playerRefs,但不需要关联的players。
在我的一个较早的问题中,有人建议以某种方式引用引用关联实体的方式重写playerRef或Player的toString()方法。不是这种情况。 N + 1查询是在访问所有playerRef实体列表时发生的。
笔记:
这是Why does this result in non-lazy fetching and N+1 select statements?的后续问题
同样没有解决方案的类似问题在这里:How to lazy load a many-to-many collection in hibernate?
最佳答案
为了解决该问题,您需要使用“批处理大小”和“提取”模式,这里的参考链接将告诉您如何克服N + 1选择问题
希望这会有所帮助
http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/
关于java - 延迟加载多对多实体时,为什么会收到N + 1个选择查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24984188/