2011-01-05 6 views
0

Nehmen wir an, ich habe eine House-Entität, die auf viele Person-Entitäten verweist. Ich lade dann ein bestehendes Haus mit 20 Bewohnern.Hibernate führt beim Aufruf von saveOrUpdate unerwünschte SELECTs aus

beginTransaction(); 
House house = houseDao.find(1L); 
commitTransaction(); 

später im Code, kann ich dann eine neue Person in das Haus hinzufügen:

... 
List<Person> people = house.getPeople(); 
people.add(new Person("Dilbert")); 
.... 

Als ich den Anruf zu tätigen:

session.saveOrUpdate(house); 

Hibernate führt 21 Anfragen: 1 WÄHLEN Sie das Haus und 20, um jede existierende Person im Haus auszuwählen.

Ich bin mir sicher, dass es ein kleines Problem von mir ist, aber was soll ich tun, damit ich eine neue Person zum Haus hinzufügen kann, ohne in dieser Situation einen so schweren Schlag auf die Datenbank zu haben?

Dies ist alles innerhalb der gleichen Sitzung erledigt.

Antwort

3

Weil Sie wirklich nicht viel über die Definition Ihrer Objekte gegeben haben, werde ich einige Annahmen machen.

  1. Home wird eine Person zu viele
  2. Person kann nur zu einem Haus gehören

Achten Sie darauf, das Haus ist definiert wie:

@Entity 
public class House implements Serializable { 
    @Id 
    private int id; 

    @OneToMany(mappedBy="house") 
    private Set<Person> people; 

    ... rest of your class 
} 


@Entity 
public class Person implements Serializable { 

    @Id 
    private int id; 

    @ManyToOne(targetEntity=House.class) 
    private House house; 

    @Column(name="person_name") 
    private String name 

    ... rest of your class 

    public Person(House house, String name) { 
     this.house = house; 
     this.name = name; 
    } 
} 

jetzt Ihr Code:

beginTransaction(); 
House house = houseDao.find(1L); 
commitTransaction() 


... your magic 

Person person = new Person(house,"Dilbert"); 

session.saveOrUpdate(person); 

In der Prüfung Wenn Sie mit Eltern-Kind-Beziehungen arbeiten (egal, ob es eins zu viele oder viele zu viele sind), können Sie die Beziehung durch das Kind herstellen. Ich bleibe in der Regel davon ab, nur generelle Aktualisierungen durch die Eltern zu machen. In Ihrem Beispiel sehen Sie, dass es viel Kopfsache ist. Wenn Sie anfangen zu arbeiten, wo es Tausende von Datensätzen gibt, wird es unmöglich.

Die andere Sache, die Sie untersuchen müssen, ist, abhängig von Ihrem Modell, subtile Änderungen an den Anmerkungen zu Ihren Listen vorzunehmen. Ein Beispiel:

@Entity 
public class House implements Serializable { 
    @Id 
    private int id; 

    @OneToMany(mappedBy="house") 
    @Fetch(FetchMode.JOIN) 
    private Set<Person> people; 

    ... rest of your class 
} 

Da @Fetch nicht Teil der JPA-Spezifikation, sondern eine Hibernate Annotations, dies, je nach Modell kann einem großen Leistungsschub geben, weil es das Haus Objekt grap wird und alle Menschen in einer einzigen Abfrage. Dies ist sehr effektiv, wenn Sie die Anzahl der Häuser und Personen begrenzen, die zum Haus gehören. Wenn Sie sehr große Ergebnismengen erhalten, ist dies möglicherweise keine gute Situation. Das nächste Beispiel könnte besser geeignet sein:

Dies wird zwei Abfragen verwenden, um alle Objekte zu greifen. Eine Abfrage für das House-Objekt (oder multiplizieren Sie Hausobjekte abhängig von der Abfrage) und Eine Abfrage für alle Personen für das/die Hausobjekt (e).

+0

Entschuldigung, In meinem Beitrag habe ich festgestellt, dass ich Set verwendet habe und Ihr Beispiel verwendet Liste. Sie können von Set zu Liste wechseln. – celias

+0

Der beste Vorschlag hier ist, die "Person" nicht das "Haus" zu bestehen. +1 –

+0

brilliant - danke Celias. Genau das, was ich gesucht habe. – digiarnie

0

Ich denke, dies ist eine mögliche Antwort auf Ihr Problem, aber vielleicht nicht in der genau wie Sie denken.

Ich habe keine Möglichkeit gefunden, Hibernate so zu gestalten, wie Sie es möchten (diese Granularität ist nicht vorhanden). Ich bin sicher, du könntest es selbst programmieren, wenn du willst.Aber wenn Sie sich wirklich Gedanken über die Performance machen, die in der Datenbank aufgetreten ist, wenden Sie sich dem Problem zu und konzentrieren Sie sich darauf, wie Sie die Belastung der Datenbank minimieren können.

Die beste Möglichkeit, Anrufe von Hibernate zur Datenbank zu optimieren, besteht darin, sicherzustellen, dass alle Hibernate-Objekttabellen indiziert sind. Hibernate ruft die Tabelle mit dem Primärschlüssel des übergeordneten Objekts auf. Diese 20 Abfragen benötigen sehr wenig DB-Verarbeitungszeit, wenn sie einen Index treffen und schnell gefunden werden. DBs sind dafür ausgelegt, viele Transaktionen wie diese abzuwickeln - der teure Teil besteht darin, die Daten auf dem Datenträger zu finden und sie für Ihre Verwendung zu laden.

Schließlich würde ich auch einen Objektcache hinzufügen. Dies könnte möglicherweise das Round-Trip zur DB eliminieren und spart Ihrem Programm eine Menge I/O-Wartezeit.

Verwandte Themen