1.1 Background ng problema

Kapag nagsimula kang magtrabaho sa mga tunay na database, maaalala mo kaagad ang pariralang "Ang maagang pag-optimize ay ang ugat ng lahat ng kasamaan." Ngayon mo lang siya naaalala sa negatibong paraan. Kapag nagtatrabaho sa isang database, ang pag-optimize ay kailangang-kailangan. At kailangan mong magtrabaho kasama ito sa yugto ng disenyo.

Ginagawa ng hibernate na maging maginhawa ang pagtatrabaho sa database. Madali kang makakakuha ng anumang mga bagay ng bata sa pamamagitan lamang ng wastong pag-annotate @OneToManyat @ManyToMany. Halimbawa:


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

At gaano kadaling makuha ang mga komento ng user:


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

At magkakaroon ka ng isang malaking sorpresa. Ang gumagamit ay may ilang libong komento. Kung magsusulat ka ng code na tulad nito, siyempre, ilo-load ng Hibernate ang lahat ng komento ng user. Ngunit ito ay magiging napakabagal, ang mga komento ay kukuha ng maraming memorya at iba pa.

Kaya pala hindi ka marunong magsulat ng ganyan! Sa teorya, oo, ngunit sa pagsasanay, hindi.

1.2 Pinapalala ang mga bagay sa mga koleksyon

Ang problema ay mas kawili-wili. Pagkatapos ng lahat, kadalasan ay hindi mo kailangan ang lahat ng komento ng user. Kahit na ipakita mo ang mga ito sa isang lugar sa kliyente, mas gusto mong gawin ito sa mga bahagi - mga pahina.

Kaya kailangan mo ng mga pamamaraan tulad nito:


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

Ang unang paraan ay nagbabalik lamang ng isang pahina ng mga komento - 50 piraso. Ibinabalik ng pangalawang paraan ang bilang ng mga pahina ng mga komento. At ito ang pinakamasama. Upang malaman lamang ang bilang ng mga komento, kailangan mong i-download ang lahat ng mga komento mula sa database!

1.3 Liwanag sa dulo ng tunnel

Samakatuwid, walang gumagamit ng aming magagandang koleksyon ng bata. Hindi, siyempre ginagamit ang mga ito, ngunit bilang bahagi lamang ng mga query sa HQL. Halimbawa tulad nito:


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

Ang magandang balita ay maaari naming ipatupad ang aming mga pamamaraan sa paraang hindi namin kailangang mag-load ng karagdagang data mula sa database. Ang masamang balita ay hindi madaling magtrabaho sa aming mga koleksyon.