Frage

Ich habe dieses Problem für eine lange Zeit jetzt habe ich das Web durchsucht und SO in der und aus und fand keine Lösung vor. Ich hoffe, dass Sie mich auf, die helfen können.

Ich habe eine Eltern-Kind-Beziehung zwischen zwei Entitäten wie folgt aus:

@Entity
public class Parent {
    // ...

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private Set<Child> children = new HashSet<Child>();

    // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY)
    private Parent parent;

    // ...
}

Die Sache ist die, dass, wenn ich ein neues Kind schaffen und es zu einem übergeordneten zuweisen, müssen die Eltern nicht mehr aktualisiert, wenn sie bereits im Cache ist.

 Parent parent = new Parent();
 em.persist(parent);

 // ...

 Child child = new Child();
 child.setParent(parent);
 em.persist(child);

 parent.getChildren().size(); // returns 0

Ich habe versucht, @PreUpdate zu verwenden, um automatisch das Kind zum Vater hinzu, wenn das Kind beibehalten wird, aber in dem Fall, wenn wir zwei Entity-Manager in zwei verschiedenen Threads haben (wie in JBoss), besteht das Problem weiterhin, bis wir nennen em.refresh(parent)

Die Frage ist also - ist es eine Möglichkeit, glatt, das Problem zu beseitigen, und dass parent.getChildren() sorgt immer wieder zurückkehren, die up-to-date Liste der Kinder

War es hilfreich?

Lösung

Die meisten ORM wird diese Art und Weise verhalten.

Das Objekt im Cache wird nicht aus der Datenbank (eine zusätzlichen Lese, die nicht notwendig ist) aktualisiert. Denken Sie auch an dem Objektmodell und die Persistenz als separates. halten das heißt Ihr Objektmodell mit sich selbst im Einklang und verlassen Sie sich nicht auf dem Persistenzmechanismus dies für Sie tun.

Also, wenn Sie das Objekt wollen die Sammlung dann hinzugefügt werden tun, dass in dem „setParent“ Code.

Die beste Vorgehensweise ist in diesem Fall in der Tat eine Seite der Beziehung die ganze Arbeit tun zu machen und lassen Sie die andere Seite auf sie aufzuschieben. Ich würde auch vorschlagen Feldzugang anstatt Methode Zugriff, auf diese Weise Sie Methoden mit größerer Flexibilität anpassen können.

Fügen Sie eine Methode, um Eltern genannt addChild

 public void addChild(Child child) {
    child.setParent0(this);
    getChildren().add(individualNeed);
 }

und dann setParent in Kindern machen:

public void setParent(Parent parent) {
   parent.addChild(child);
}

setParent0 in Kind ist Eigentum stter für Eltern auf Kind.

public void setParent0(Parent parent) {
   this.parent = parent;
}

Ich würde auch vorschlagen, dass die „getChildren“ Methode eine unveränderliche Sammlung zurückgeben, so dass Entwickler inadvertantly nicht diese Methode nicht verwenden (ich auf die harte Art und Weise in all diesem gelernt).

Eine weitere Sache, Sie null Prüfcodes und andere defensive Stücke in dem obigen Code haben sollte, ich es verlassen für Klarheit aus.

Andere Tipps

Ziemlich sicher, dass Ihr Problem hier ist Ihre Cascade Einstellungen.

@Entity
public class Parent {
   // ...

   @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, 
      cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private Set<Child> children = new HashSet<Child>();

   // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    private Parent parent;

    // ...
}

diese Kaskade Einstellungen verwenden wird an untergeordnete Objekte bestehen und Updates kaskadieren.

zB.

Parent parent = new Parent();
em.persist(parent);

// ...

Child child = new Child();
child.setParent(parent);
em.persist(child); //will cascade update to parent

parent.getChildren().size(); // returns 1

oder

Parent parent = new Parent();
Child child = new Child();
parent.setChild(parent);
em.persist(parent); //will cascade update to child

child.getParent(); // returns the parent

Weitere Informationen dazu finden Sie unter Hibernate Annotations

In Bezug auf Ihre Frage mit Caching, ist dies ein sehr häufiges Problem, wenn Sie gegen die gleiche Datenbank mehrere VMs mit separatem Caches ausgeführt wird. Es heißt „Cache-Drift“ bezeichnet.

Die meisten Hibernate freundliche Cache-Implementierungen (ehcache, OSCache und SwarmCache) einen verteilten Cache eingebauten, dass verwendet werden kann, um die Caches zu synchronisieren. Die verteilten Cache, in der Regel sendet Multicast-Nachrichten den Zustand des Cache zu aktualisieren. Macht einen Cache zweite Ebene Räumung durch SessionFactory.evict (Klasse, id), zum Beispiel, wird eine Ungültigkeitsmeldung führen zu dem anderen Caches in dem Cluster gesendet werden, die in anderen Cache-Speicher keine andere Kopien des Objekts ungültig werden.

Abhängig von der Bereitstellung kann die Multicast oder möglicherweise für Sie nicht akzeptabel sein. Wenn dies nicht der Fall müssen Sie möglicherweise eine Single-Cache-Lösung wie Memcached verwenden.

Ich persönlich fand die Konfiguration eh Cache des verteilten Cache sehr einfach.

EH-Cache diskutiert das Problem in etwas mehr Detail hier: http://ehcache.org/documentation/ distributed_caching.html

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top