Hibernate正在做多个select请求而不是一个(使用join fetch)

我有以下查询,我希望在单个选择请求中运行:

@NamedQuery(name=Game.GET_GAME_BY_ID1, query = "SELECT g FROM Game g " + "JOIN FETCH g.team1 t1 " + "JOIN FETCH t1.players p1 " + "JOIN FETCH p1.playerSkill skill1 " + "where g.id=:id") 

问题是所有内容都是由单独的多个查询提取的。 我只希望在一个请求中获取团队和团队的玩家以及每个玩家的技能。 但相反,我有多个选择查询来获取每个球队,球员,每个球员的统计数据和技能。

以下是与注释一起使用的实体:

游戏实体:

 public class Game implements Serializable { private Integer id; private Integer dayNumber; private Long date; private Integer score1; private Integer score2; private Team team1; private Team team2; .... @ManyToOne(fetch=FetchType.EAGER) @Fetch(FetchMode.JOIN) @JoinColumn(name="team_id1") public Team getTeam1() { return team1; } public void setTeam1(Team team1) { this.team1 = team1; } // uni directional many to one association to Team @ManyToOne(fetch=FetchType.EAGER) @Fetch(FetchMode.JOIN) @JoinColumn(name="team_id2") public Team getTeam2() { return team2; } public void setTeam2(Team team2) { this.team2 = team2; } } 

团队实体:

 public class Team implements Serializable { ... private Set players; ... @OneToMany(mappedBy="team", targetEntity=Player.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) @OrderBy(value="batOrder, pitRotationNumber ASC") public Set getPlayers() { return players; } public void setPlayers(Set players) { this.players = players; } } 

玩家实体:

 public class Player implements Serializable { private PlayerStat playerStats; private PlayerSkill playerSkill; ... @OneToOne(mappedBy="player", cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) public PlayerStat getPlayerStats() { return this.playerStats; } public void setPlayerStats(PlayerStat playerStats) { this.PlayerStats = playerStats; } ... @OneToOne(mappedBy="player", fetch=FetchType.LAZY, cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) public PlayerSkill getPlayerSkill() { return this.playerSkill; } public void setPlayerSkill(PlayerSkill playerSkill) { this.playerSkill = playerSkill; } } 

你能指出所犯的错误吗? 我需要一个选择查询来加载游戏,它是团队,团队的玩家和每个玩家的技能。

编辑1:这里是postgresql日志(它的一部分),纯SQL查询: http : //pastebin.com/Fbsvmep6

为简单起见,在这个问题中更改了表的原始名称,Game是GamelistLeague,Team是TeamInfo,还有BatterStats和PitcherStats而不是一个PlayerStat

日志中的第一个查询是上面这个问题中显示的查询(命名查询),如果我直接在数据库中执行它,则根据需要返回所有内容。

您遇到了一个众所周知的问题,即“N + 1选择”。 简而言之,当您选择父实体时,会发生“N + 1选择”问题,而hibernate将使用OneToOne为与父项相关的子项进行额外选择。 因此,如果数据库中有“N”个父子记录,则hibernate将为所有父项提供一个选择,然后将每个子项分开选择,使总N + 1选择。
hibernate中存在两种“N + 1”问题的方法:
1.“加入Fetch” 所有 OneToOne孩子。
2.启用二级缓存并在OneToOne子级上使用@Cache批注。

您的问题是您没有“加入”所有OneToOne孩子。 您必须“加入”它们全部,包括传递子项(从子项本身或集合中引用的实体)。

使OneToOne懒惰(因为它默认情况下急切)只是部分解决方案,因为只有当你访问孩子的某个getter时,hibernate才会为孩子做出选择,但从长远来看,它仍然会进行所有N次选择。

辅助查询来自:

 @ManyToOne(fetch=FetchType.EAGER) @Fetch(FetchMode.JOIN) @JoinColumn(name="team_id2") public Team getTeam2() { return team2; } 

所以,你需要:

  1. 使所有协会LAZY。 默认情况下, 所有@ManyToOne和@OneToOne关联都是EAGER,因此最好让它们成为LAZY并且仅在查询的基础上覆盖获取计划。

  2. 删除@Fetch(FetchMode.JOIN) ,它本质上是一个EAGER fetch指令。 在你的情况下,不仅是team2属性被提取,而是其玩家和技能。