1.1 Предистория на проблема
Когато започнете да работите с реални бази данни, веднага ще си спомните фразата „Преждевременната оптимизация е коренът на всяко зло“. Само сега си спомняш за нея по негативен начин. При работа с база данни оптимизацията е незаменима. И трябва да работите с него още на етапа на проектиране.
Hibernate прави работата с базата данни много удобна. Можете лесно да получите всяHowви дъщерни обекти само чрез правилно анотиране @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();
И ще ви очаква голяма изненада. Потребителят има няколко хиляди коментара. Ако напишете code по този начин, 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);
}
}
Първият метод връща само една page с коментари - 50 броя. Вторият метод връща броя на страниците с коментари. И това е най-лошото. За да разберете просто броя на коментарите, трябваше да изтеглите всички коментари от базата данни!
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