Hibernate est de faire de la sélection multiple requêtes au lieu d'une seule (à l'aide de join fetch)
J'ai la requête suivante qui je m'attends à exécuter dans une sélection unique de demande:
@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")
Le problème, c'est que tout est extraite par de multiples requêtes.
Je ne veux que de l'Équipe et des joueurs de l'équipe et de chaque joueur de compétences à récupérer en une seule requête. Mais au lieu de cela j'ai eu plusieurs requêtes select pour récupérer chaque équipe, joueur, chaque joueur stats et des compétences.
Ici sont des entités utilisées avec des annotations donné:
Jeu Entité:
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;
}
}
De L'Équipe De L'Entité:
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;
}
}
Joueur De L'Entité:
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;
}
}
Pourriez-vous point sur les erreurs commises?
J'ai besoin d'une requête select pour charger un jeu, c'est les équipes, les joueurs de l'équipe et de chaque joueur de compétences.
EDIT 1:
voici postgresql journal (une partie de), pur requêtes sql:
http://pastebin.com/Fbsvmep6
Origine des noms de tables sont modifiées dans cette question, pour des raisons de simplicité,
Le jeu est GamelistLeague, l'Équipe est TeamInfo, et il y a BatterStats et PitcherStats au lieu d'un PlayerStat
La première requête à partir des journaux est celui affiché dans cette question ci-dessus (du nom de la requête) qui, si je l'exécuter directement dans la base de données, les rendements tout en tant que de besoin.
veuillez prendre un coup d'oeil sur modifier. Je peux essayer de désactiver le chargement différé, mais plus tard, si j'ai besoin d'être défini comme paresseux pour d'autres requêtes qui ne devrait pas chercher avidement les joueurs.
Hibernate... rendre les gens intelligents exécuter stupide requêtes depuis 2001. Peut-être temps d'abandonner le Hibernate inutilités et de passer à quelque chose de plus proche du metal 🙂
hahaha 😀
Je voulais juste dire quelque chose à l'Lance Java. Je vais fossé hibernate et l'utilisation mybatis. de la bonne seigneur est hibernate faire de moi un réel stupide.
OriginalL'auteur maximus | 2015-01-14
Vous devez vous connecter pour publier un commentaire.
Vous rencontrez un problème connu, une.k.un. le "N+1 selects".
En bref, le "N+1 selects" problème se produit lorsque vous sélectionnez une entité mère et hibernate va faire d'autres pour un enfant liés à la société mère avec OneToOne. Donc, si vous avez "N" parent-enfant des enregistrements dans la base de données, hibernate va obtenir tous les parents avec un select et ensuite obtenir chaque enfant est séparé de sélectionner, soit un total de N+1 selects.
Il existe deux approches pour le "N+1" problème de mise en veille prolongée:
1. "Join Fetch" tous OneToOne enfants.
2. Activer le cache de second niveau et de l'utilisation @Cache annotation sur le OneToOne enfants.
Votre problème est que vous n'avez pas "join fetch" tous les OneToOne enfants.
Vous devez "join fetch" tous, y compris les transitive enfants (entités référencées auprès des enfants eux-mêmes, ou au sein de la collection).
Faire OneToOne paresseux (parce que sa hâte par défaut) n'est qu'une solution partielle, parce que hibernate va faire un select pour un enfant que lorsque vous accédez à certains de lecture à l'enfant, mais à long terme ça va encore prendre toutes les N sélectionne.
OriginalL'auteur outdev
Le secondaire requêtes proviennent de:
Donc, vous avez besoin de:
Faire toutes les associations PARESSEUX. Par défaut, tous @ManyToOne et @OneToOne associations sont IMPATIENTS, il est donc préférable de les avoir PARESSEUX et remplacez uniquement les fetch plan sur une requête de base.
Supprimer la
@Fetch(FetchMode.JOIN)
, qui est essentiellement une AVIDE d'extraction de la directive. Dans votre cas, non seulement le team2 propriété est par les cheveux, mais ses joueurs et de compétences.Vous devez définir explicitement PARESSEUX pour OneToOne et ManyToOne trop. Ensuite utiliser join fetch dans votre requête.
Je dois faire join fetch même si je n'ai pas besoin de ces entités pour être chargé?
Vous n'avez qu'à JOINDRE les RÉCUPÉRER quand vous en avez besoin. Si vous n'avez pas à les charger, il suffit de charger l'entité mère. Dans ce scénario, tous les PARESSEUX, les associations ne seront initialisés lors de temps d'accès. Sauf si vous accédez à la paresse des associations, ils ne seront jamais déclencheur secondaire sélectionne.
Désolé mais il semble que cela ne fonctionne toujours pas. J'ai fait le test avec cette requête. Avant il n'était pas de chargement en raison peut-être antérieur extrait passés avec succès. Pas sûr. Mais même après avoir changé comme vous l'avez mentionné en réponse, le code, il est toujours en charge de l'équipe avec sélection de la demande est allé à la db.
OriginalL'auteur Vlad Mihalcea