8

私は長い間この問題を抱えています。私はウェブとSOを出し入れして検索しましたが、まだ解決策を見つけられませんでした。あなたがそれについて私を助けてくれることを願っています。

私は次のような2つのエンティティ間に親子関係を持っています:

@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;

    // ...
}

新しい子を作成して親に割り当てると、親がすでにキャッシュにある場合、親は更新されません。

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

 // ...

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

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

@PreUpdateを使用して、子が永続化されたときに子を親に自動的に追加しようとしましたが、2つの異なるスレッドに2つのエンティティマネージャーがある場合(JBossのように)、呼び出すまで問題は引き続き存在しますem.refresh(parent)

したがって、問題は、問題をスムーズに排除し、parent.getChildren()常に最新の子のリストを返すようにする方法はありますか?

4

3 に答える 3

8

ほとんどのORMはこのように動作します。

キャッシュ内のオブジェクトはデータベースから更新されません(不要な追加の読み取り)。また、オブジェクトモデルと永続性を別々のものと考えてください。つまり、オブジェクトモデルをそれ自体と一貫性のある状態に保ち、永続化メカニズムに依存してこれを行わないでください。

したがって、オブジェクトをコレクションに追加する場合は、「setParent」コードで追加します。

この場合のベストプラクティスは、実際には、関係の一方の側にすべての作業を行わせ、もう一方の側にそれを延期させることです。また、メソッドアクセスではなくフィールドアクセスを使用することをお勧めします。そうすれば、メソッドをより柔軟にカスタマイズできます。

addChildというメソッドを親に追加します

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

次に、子でsetParentを作成します。

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

子のsetParent0は、子の親のプロパティstterです。

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

また、開発者が誤ってこのメソッドを使用しないように、「getChildren」メソッドが不変のコレクションを返すことをお勧めします(私はこれらすべてで難しい方法を学びました)。

もう1つ、上記のコードにはnullチェックコードとその他の防御的な部分が必要です。わかりやすくするために省略しました。

于 2009-07-30T14:42:41.783 に答える
4

ここでの問題はカスケード設定です。

@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;

    // ...
}

これらのカスケード設定を使用すると、子オブジェクトへの永続化と更新がカスケードされます。

例えば。

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

また

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

child.getParent(); // returns the parent

これに関する詳細は、HibernateAnnotationsにあります。

于 2011-09-28T12:55:49.523 に答える
1

キャッシュに関する問題に関して、これは、別々のキャッシュを持つ同じデータベースに対して複数のVMを実行している場合に非常に一般的な問題です。これは「キャッシュドリフト」と呼ばれます。

ほとんどの休止状態に適したキャッシュ実装(ehcache、OSCache、SwarmCache)には、キャッシュの同期に使用できる分散キャッシュが組み込まれています。分散キャッシュは、通常、キャッシュの状態を更新するマルチキャストメッセージを送信します。たとえば、SessionFactory.evict(Class、id)によって第2レベルのキャッシュエビクションを実行すると、無効化メッセージがクラスター内の他のキャッシュに送信され、他のキャッシュ内のそのオブジェクトの他のコピーが無効になります。

展開によっては、マルチキャストが受け入れられる場合と受け入れられない場合があります。そうでない場合は、memcachedのような単一キャッシュソリューションを使用する必要があるかもしれません。

私は個人的に、ehキャッシュの分散キャッシュの構成が非常に簡単であることに気づきました。

EHキャッシュでは、この問題についてもう少し詳しく説明しています:http ://ehcache.org/documentation/distributed_caching.html

于 2010-11-16T17:03:06.700 に答える