2012-02-23 28 views
13

で効率的にidで複数のエンティティをロードするので、Imは休止状態4

for(Integer songId:songGroup.getSongIds()) 
{ 
    session = HibernateUtil.getSession(); 
    Song song = (Song) session.get(Song.class,id); 
    processSong(song); 
} 

idで特定のエンティティのインスタンスの数を取得し、これはIDごとSQLクエリを生成し、それは私がやるべきことを私に発生しましたこれは1つですが、クエリを実行する以外は、1つの呼び出しで複数のエンティティを取得する方法が見つかりませんでした。だから私は、クエリに

return (List) session.createCriteria(Song.class) 
     .add(Restrictions.in("id",ids)).list(); 

を書いたが、私は第二レベルのキャッシュを有効にした場合、それは私の古い方法は、(彼らは以前に要求されていた場合)、第2レベルのキャッシュからオブジェクトを返すことができるということを意味するが、私はありませんクエリは常にデータベースに行きます。

これを行う正しい方法は何ですか?

+0

これを行う方法を理解しましたか? – FGreg

答えて

8

ここでやることは、HibernateがCriteriaの特別なケースハンドリングを行うことです。これは一種の質問です。

あなた自身で行う必要がありますが、難しくありません。 SessionFactory.getCache()を使用すると、キャッシュされたオブジェクトの実際のストレージへの参照を取得できます。次のようなものを実行します。

for (Long id : allRequiredIds) { 
    if (!sessionFactory.getCache().containsEntity(Song.class, id)) { 
    idsToQueryDatabaseFor.add(id) 
    } else { 
    songs.add(session.get(Song.class, id)); 
    } 
} 

List<Song> fetchedSongs = session.createCriteria(Song.class).add(Restrictions.in("id",idsToQueryDatabaseFor).list(); 
songs.addAll(fetchedSongs); 

そして、キャッシュからの曲がそこから取り出され、そして単一selectに引か取得されていないものを取得します。

+0

感謝します –

0

休止状態の第2レベルキャッシュと休止状態のクエリキャッシュには違いがあります。 次のリンクは本当によくそれを説明する:一言で言えばhttp://www.javalobby.org/java/forums/t48846.html

、 をあなたは、あなたがデータベースを減らすことができ、同じパラメータで何度も同じクエリを使用している場合は、両方の組み合わせを使用してヒット。

0

また、IDのリストをソートし、連続したIDのサブシーケンスを識別し、単一のクエリでこれらのサブシーケンスのそれぞれを照会することもできます。例えば、List<Long> ids与えられた、(あなたはJavaでペアクラスを持っていると仮定して)次の操作を行います

List<Pair> pairs=new LinkedList<Pair>(); 
List<Object> results=new LinkedList<Object>(); 
Collections.sort(ids); 
Iterator<Long> it=ids.iterator(); 

Long previous=-1L; 
Long sequence_start=-1L; 
while (it.hasNext()){ 
    Long next=it.next(); 

    if (next>previous+1) { 
     pairs.add(new Pair(sequence_start, previous)); 
     sequence_start=next; 
    } 
    previous=next; 
} 
pairs.add(new Pair(sequence_start, previous)); 

for (Pair pair : pairs){ 
    Query query=session.createQuery("from Person p where p.id>=:start_id and p.id<=:end_id"); 
    query.setLong("start_id", pair.getStart()); 
    query.setLong("end_id", pair.getEnd()); 

    results.addAll((List<Object>)query.list()); 

} 
1

あなたはIDが存在することがわかっている場合は、あなたが実際にDBを押すことなく、プロキシを作成するためにload(..)を使用することができます。

戻る与えられた識別子を有する特定のエンティティ・クラスの永続的なインスタンス、インスタンスが存在すると仮定すると、指定されたロックモードを取得します。

List<Song> list = new ArrayList<>(ids.size()); 
for (Integer id : ids) 
    list.add(session.load(Song.class, id, LockOptions.NONE)); 

バッチフェッチ設定されている場合を使用して、あなたは非識別子アクセサにアクセスしたら、Hibernateはキャッシュをチェックし、必要に応じてDBにフォールバック。

IDが存在しない場合は、オブジェクトがロードされるとObjectNotFoundExceptionが発生します。これはあなたのコードのどこかで、実際には例外を期待しないかもしれません - 最後に単純なアクセサを使用しています。したがって、IDが存在するかどうかを100%確かめるか、少なくとも期待通りにObjectNotFoundExceptionを強制してください。リストを作成した直後。