gpt4 book ai didi

java - 为什么 Hibernate 在使用 @Fetch(FetchMode.JOIN) 时执行多个 SELECT 查询而不是一个

转载 作者:搜寻专家 更新时间:2023-10-30 19:50:32 24 4
gpt4 key购买 nike

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

@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<Player> players;
...
@OneToMany(mappedBy="team", targetEntity=Player.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@Fetch(FetchMode.JOIN)
@OrderBy(value="batOrder, pitRotationNumber ASC")
public Set<Player> getPlayers() {
return players;
}


public void setPlayers(Set<Player> 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 将通过一次选择获得所有 parent ,然后将每个 child 分开选择,总共 N+1 次选择。
hibernate中的“N+1”问题有两种解决方法:
1. "Join Fetch"所有 OneToOne children.
2. 开启二级缓存,并在OneToOne子节点上使用@Cache注解。

你的问题是你没有“join fetch”所有的 OneToOne child 。您必须“联合获取”它们,包括可传递的子项(从子项本身或集合中引用的实体)。

使 OneToOne 变得惰性(因为默认情况下它是急切的)只是部分解决方案,因为仅当您访问子对象的某些 getter 时,hibernate 才会为子对象进行选择,但从长远来看,它仍会进行所有 N 个选择。

关于java - 为什么 Hibernate 在使用 @Fetch(FetchMode.JOIN) 时执行多个 SELECT 查询而不是一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27935761/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com