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

幸いなことに、データベースから追​​加のデータをロードする必要がない方法でメソッドを実装できることです。悪いニュースは、私たちのコレクションを扱うのは簡単ではないということです。