1.1 問題の背景
実際のデータベースを扱い始めると、「時期尚早の最適化は諸悪の根源である」という言葉をすぐに思い出すでしょう。今になって初めて、あなたは彼女のことを否定的な意味で思い出しました。データベースを操作する場合、最適化は不可欠です。そして、設計段階ですでにそれを扱う必要があります。
Hibernate を使用すると、データベースの操作が非常に便利になります。@OneToMany
とに適切に注釈を付けるだけで、子オブジェクトを簡単に取得できます@ManyToMany
。例:
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
public List<Comment> comments;
}
ユーザーのコメントを取得するのは非常に簡単です。
User user = session.get(User.class, 1);
List<Comment> comments = user.getComments();
そして、あなたは大きな驚きに遭遇するでしょう。ユーザーには数千のコメントがあります。このようなコードを作成すると、Hibernate はもちろんユーザーのコメントをすべてロードします。ただし、非常に遅くなり、コメントに多くのメモリが消費されます。
だからそんなこと書けないんだよ!理論的にはそうですが、実際には違います。
1.2 コレクションで問題が悪化する
問題はさらに興味深いものです。結局のところ、通常、すべてのユーザーのコメントが必要になることはありません。クライアント上のどこかに表示する場合でも、ページごとに分割して表示することをお勧めします。
したがって、次のようなメソッドが必要です。
public class CommentsManager {
private static final PAGE_SIZE = 50;
public List<Comment> getCommentsPage(int userId, int pageIndex){
User user = session.get(User.class, userId);
List<Comment> comments = user.getComments();
return comments.subList(pageIndex * PAGE_SIZE, PAGE_SIZE);
}
public int getCommentsPageCount(int userId) {
User user = session.get(User.class, userId);
List<Comment> comments = user.getComments();
return Math.ceil( comments.size()/PAGE_SIZE);
}
}
最初のメソッドは、1 ページのコメント (50 個) のみを返します。2 番目のメソッドは、コメントのページ数を返します。そしてこれは最悪です。コメントの数を単純に調べるには、データベースからすべてのコメントをダウンロードする必要があります。
1.3 トンネルの終わりの光
したがって、誰も私たちの素晴らしい子コレクションを使用しません。いいえ、もちろん使用されますが、HQL クエリの一部としてのみ使用されます。たとえば次のようになります。
public class CommentsManager {
private static final PAGE_SIZE = 50;
public List<Comment> getCommentsPage(int userId, int pageIndex){
String hql = "select comments from User where id = :id";
Query<Comment> query = session.createQuery( hql, Comment.class);
query.setParametr("id", userId);
query.setOffset(pageIndex * PAGE_SIZE);
query.setLimit(PAGE_SIZE);
return query.list();
}
public int getCommentsPageCount(int userId) {
String hql = "select count(comments) from User where id = :id";
Query<Integer> query = session.createQuery( hql, Integer.class);
query.setParametr("id", userId);
return Math.ceil(query.singleResult()/PAGE_SIZE);
}
}
幸いなことに、データベースから追加のデータをロードする必要がない方法でメソッドを実装できることです。悪いニュースは、私たちのコレクションを扱うのは簡単ではないということです。
GO TO FULL VERSION