2016-09-15 2 views
1

Beim Testen der Implementierung von JPA in Spring fand ich heraus, dass meine Abfrage zweimal statt einmal abfragt.Warum fragt Hibernate zweimal ab?

@Data 
@Entity 
@Table(name = "superfan_star") 
public class Star implements Serializable 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false) 
    private int id; 
    private String name; 
    private String nickname; 
    private String description; 
    private String thumbnail; 
    private String backgroundImage; 
    private Date created; 
    private Date updated; 

    @OneToMany(fetch = FetchType.EAGER) 
    @JoinColumn(name = "starId", referencedColumnName = "id", insertable = false, updatable = false) 
    private Set<Media> medias; 
} 

Dies ist eine Modellklasse.

@Service 
public class SuperfanStarService 
{ 
    @Autowired 
    private StarRepository starRepository; 

    @PersistenceContext 
    private EntityManager em; 

    @Transactional 
    public List<Star> getStars() 
    { 
     QStar qStar = QStar.star; 
     QMedia qMedia = QMedia.media; 

     List<Star> stars = 
       new JPAQuery(em) 
       .from(qStar) 
       .where(qStar.id.eq(19)) 
       .list(qStar); 

     return stars; 
    } 
} 

Dies ist meine Serviceklasse.

20160915 20: 52: 59,119 [http-NiO-8080-exec-1] DEBUG j.sqlonly - org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract (ResultSetReturnImpl.java:82) 9 Wählen Sie star0_.id als id1_2_, star0_.background_image als backgrou2_2_, star0_.created als created3_2_, star0_.description als descript4_2_, star0_.name als name5_2_, star0_.nickname als nickname6_2_, star0_.thumbnail als thumbnai7_2_, star0_.updated als updated8_2_ von superfan_star star0_ Exklusionsverknüpfung superfan_media medias1_ auf star0_.id = medias1_.star_id wo star0_.id = 19

20160915 20: 52: 59.173 [http-nio-8080-exec-1] DEBUG j.sqlonly - org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract (ResultSetReturnImpl.java:82) 9. Wählen Sie medias0_.star_id als star_id11_2_0_, medias0_ .id als id1_1_0_, medias0_.id als id1_1_1_, medias0_.created als created2_1_1_, medias0_.description als descript3_1_1_, medias0_.end_time als end_time4_1_1_, medias0_.is_approve als is_appro5_1_1_, medias0_.is_approved_final als is_appro6_1_1_, medias0_.is_pushed als is_pushe7_1_1_ , medias0_.is_represent als is_repre8_1_1_, medias0_.length als length9_1_1_, medias0_.released als release10_1_1_, medias0_.star_id als star_id11_1_1_, medias0_.teleport_media_id als telepor12_1_1_, medias0_.thumbnail als thumbna13_1_1_, medias0_.title als title14_1_1_, medias0_.work_end als work_en15_1_1_, medias0_.work_start als work_st16_1_1_, medias0_.youtube_id als youtube17_1_1_, medias0_.youtube_title als youtube18_1_1_ von superfan_media medias0_ wo medias0_.star_id = 19

Wie Sie sehen können, es fragt zweimal anstelle von einmal, wahrscheinlich wegen inversem update? Gibt es eine Möglichkeit, mein JPA-Modell nur einmal abzufragen?

+0

Zwar gibt es eine akzeptierte Antwort, die ich dort vielleicht vermuten etwas anderes spielt hier. Ich bemerke, dass Sie eine Lombok @Data haben, die, wie ich glaube, auf allen Feldern Equal und Hashcode überschreibt, was in einer JPA-Entität gefährlich ist, da sie viele zusätzliche Daten auslösen kann, wenn assoziierte Elemente zu Hash-basierten Sammlungen hinzugefügt werden. Was passiert, wenn Sie dies entfernen? –

+0

@AlanHay Ja, ich habe herausgefunden, dass Lombok Probleme für Listen verursacht, da es Medien für jeden Star abfragt. Ich versuche zu sehen, ob es einen Weg gibt, Lombok zu benutzen, ohne alles abzufragen, aber es scheint keinen Weg zu geben. – Aesis

+0

Als Antwort –

Antwort

1

Dies funktioniert wie erwartet. Die erste Abfrage ruft die Entität Star mit ID = 19 aus der Datenbank ab, und die zweite Abfrage ruft die verknüpften Entitäten Media für diese Entität Star aus der Datenbank ab. (Schauen Sie sich das Protokoll der SQL-Anweisungen genau an, um zu verstehen, was abgefragt wird).

Beachten Sie, dass FetchType.EAGER auf dem medias Feld in der Klasse angegeben Star:

@OneToMany(fetch = FetchType.EAGER) 
@JoinColumn(name = "starId", referencedColumnName = "id", insertable = false, updatable = false) 
private Set<Media> medias; 

Eager fetching bedeutet, dass wenn Sie eine Abfrage für einen oder mehrere Star Objekte tun, Hibernate bekommt sofort die verknüpften Media Objekte - im Gegensatz zu faul holen, was bedeutet, dass die zweite Abfrage nicht sofort ausgeführt wird, sondern nur bei Bedarf (wenn Sie auf die Elementvariable medias zugreifen).

+0

hinzugefügt Ah, danke. Ich dachte, dass der innere Join der ersten Abfrage ausreicht, um das Objekt zu erhalten, und wusste nicht, dass eine zweite Abfrage benötigt wird, um die Medieneinheit zu verbinden. – Aesis

1

Während es eine akzeptierte Antwort gibt, vermute ich, dass hier vielleicht noch etwas anderes im Spiel ist.Ich bemerke, dass Sie eine Lombok @Data haben, die 10 und hashcode() basierend auf allen Feldern überschreibt, die in einer JPA-Entität gefährlich ist, da sie viele zusätzliche Daten auslösen kann, wenn verknüpfte Elemente zu Hash-basierten Sammlungen hinzugefügt werden.

Ja, ich habe herausgefunden, dass Lombok Probleme für Listen verursacht, da es Medien für jeden Star abfragt. Ich versuche zu sehen, ob es einen Weg gibt, Lombok zu benutzen, ohne alles abzufragen, aber es scheint keinen Weg zu geben.

Erstens würde ich vorschlagen, nicht equals() und hashcode() basierend auf allen Bereichen Ihres Unternehmens Umsetzung: dass die Ursache des Problems ist und macht keinen Sinn sowieso - sie auf einem einzigartigen Business-Schlüssel stützen, wenn Sie eine zur Verfügung haben. Im Wesentlichen sind zwei Entitäten gleich, wenn sie dieselbe ID haben, aber siehe hier jedoch:

The JPA hashCode()/equals() dilemma.

Zusätzlich hashcode() sollte auf unveränderlichen Felder basieren - siehe hier:

http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/.

Lomboks @Data aggregiert nur einzelne Annotationen. So können Sie es entfernen, verwenden Sie die einzelnen @Getter@Setter und @ToString Lombok Anmerkungen und schreiben Sie Ihre eigene vernünftige Implementierungen von equals() und hashCode() bei Bedarf:

https://projectlombok.org/features/Data.html

Verwandte Themen