2011-01-05 6 views
0

私は多くのPersonエンティティにマップするHouseエンティティを持っているとしましょう。私は20人の居住者を持っている既存の家を読み込みます。HibernateはsaveOrUpdateの呼び出しで望ましくないSELECTを実行しています

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

後のコードでは、私はその後、家に新しい人を追加することができます。

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

私が呼び出します

session.saveOrUpdate(house); 

Hibernateは21個のクエリを実行:1にしますハウスを選択し、ハウス内の既存の人物をそれぞれ20人ずつ選択します。

私はそれが自分のところでは小さな問題だと確信していますが、このような状況でデータベースに大きな被害を与えずに新しい人物を家に追加できるようにするにはどうすればよいですか?

これはすべて同じセッション内で実行されます。

答えて

3

実際にあなたのオブジェクトの定義に多くのことを与えていないので、私はいくつか前提を作るつもりです。

  1. 者へのホームは人だけで家が同じように定義されていることを確認し1ハウス

に属することができ、多くの

  • の一つである:今、あなたのコード

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

    beginTransaction(); 
    House house = houseDao.find(1L); 
    commitTransaction() 
    
    
    ... your magic 
    
    Person person = new Person(house,"Dilbert"); 
    
    session.saveOrUpdate(person); 
    

    試験中あなたが親子関係で働いているとき(それは問題ではありませんが、それは多かれ少なかれ多数あります)、あなたは子供を通して関係を作ることができます。私は一般的に、親を通してブランケットの更新をすることから離れています。あなたの例では、それは頭の上にたくさんあることがわかります。数千のレコードがある場所で作業を開始すると、不可能になります。

    あなたのモデルによっては、リストに注釈を微妙に変更することもあります。例:

    @Entity 
    public class House implements Serializable { 
        @Id 
        private int id; 
    
        @OneToMany(mappedBy="house") 
        @Fetch(FetchMode.JOIN) 
        private Set<Person> people; 
    
        ... rest of your class 
    } 
    

    @Fetchは、JPAの仕様の一部ではありませんが、それは家のオブジェクトとすべての人々をGRAPますので、休止状態アノテーションは、これは、お使いの機種によっては、大きなパフォーマンスの向上を与えることができることを考えます単一のクエリであなたが家の数や家に属する人の数を制限している場合、これは非常に効果的です。非常に大きな結果を得ている場合、これは良い状況ではないかもしれません。

    @Entity 
    public class House implements Serializable { 
        @Id 
        private int id; 
    
        @OneToMany(mappedBy="house") 
        @Fetch(FetchMode.SUBSELECT) 
        private Set<Person> people; 
    
        ... rest of your class 
    } 
    

    これは2つのクエリーを使用してすべてのオブジェクトを取得します。 Houseオブジェクトの1つのクエリー(またはクエリーに応じてハウスオブジェクトを多重化する)と、ハウスオブジェクトのすべての人物を1つのクエリー。

  • +0

    申し訳ありませんが、私のポストでは、私はSetとあなたのサンプル使用Listを使用していることを認識しました。 SetからListに切り替えることができます。 – celias

    +0

    ここでは、「ハウス」ではなく「人物」を維持することを提案しています。 +1 –

    +0

    brilliant - 感謝のセリア。まさに私が探していたもの。 – digiarnie

    0

    私はこれがあなたの問題に対する潜在的な答えだと思っていますが、あなたが考えている正確な方法ではないかもしれません。

    私は、Hibernateをあなたが望むように振る舞わせる方法を見つけられませんでした(粒度レベルはありません)。あなたが望むなら、自分でコードを書くことができると確信しています。しかし、DBのパフォーマンスが本当に心配している場合は、問題を回し、DBの負荷を最小限にする方法に焦点を当ててください。

    HibernateからDBへの呼び出しを最適化する最適な方法は、すべてのHibernateオブジェクトテーブルがインデックスされていることを確認することです。 Hibernateは、親オブジェクトの主キーを使用してテーブルを呼び出します。これらの20のクエリは、インデックスにヒットしてすぐに見つかった場合、DB処理時間はほとんどかかりません。 DBは、このような多くのトランザクションを処理するために作られています。高価な部分は、ディスク上にデータを配置し、使用するためにロードすることです。

    最後に、オブジェクトキャッシュも追加します。これにより、DBへのラウンドトリップが潜在的に排除され、プログラムのI/O待ち時間が大幅に短縮されます。

    関連する問題