1.1 Achtergrond van het probleem

Wanneer u met echte databases gaat werken, herinnert u zich meteen de uitdrukking "Voortijdige optimalisatie is de wortel van alle kwaad." Pas nu herinner je je haar op een negatieve manier. Bij het werken met een database is optimalisatie onmisbaar. En je moet er al in de ontwerpfase mee werken.

Hibernate maakt het werken met de database erg handig. U kunt eenvoudig alle onderliggende objecten krijgen door de @OneToManyen correct te annoteren @ManyToMany. Voorbeeld:


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL)
   @JoinColumn(name = "user_id")
   public List<Comment> comments;
}

En hoe gemakkelijk het is om de opmerkingen van de gebruiker te krijgen:


User user = session.get(User.class, 1);
List<Comment> comments = user.getComments();

En je staat voor een grote verrassing. De gebruiker heeft enkele duizenden opmerkingen. Als je op deze manier code schrijft, laadt Hibernate natuurlijk alle opmerkingen van de gebruiker. Maar het zal erg traag zijn, opmerkingen zullen veel geheugen in beslag nemen, enzovoort.

Daarom kun je zo niet schrijven! In theorie wel, maar in de praktijk niet.

1.2 Het erger maken met incasso's

Het probleem is nog interessanter. Meestal heb je immers nooit alle opmerkingen van de gebruiker nodig. Zelfs als je ze ergens op de client weergeeft, doe je dat het liefst in delen - pagina's.

Je hebt dus methoden als deze nodig:


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

De eerste methode retourneert slechts één pagina met opmerkingen - 50 stukjes. De tweede methode retourneert het aantal pagina's met opmerkingen. En dit is het ergste. Om eenvoudig het aantal reacties te weten te komen, moest u alle opmerkingen uit de database downloaden!

1.3 Licht aan het einde van de tunnel

Daarom gebruikt niemand onze prachtige kindercollecties. Nee, natuurlijk worden ze gebruikt, maar alleen als onderdeel van HQL-query's. Bijvoorbeeld zo:


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

Het goede nieuws is dat we onze methoden zo kunnen implementeren dat we geen extra gegevens uit de database hoeven te laden. Het slechte nieuws is dat het niet gemakkelijk is om met onze collecties te werken.