1.1 Sorunun arka planı
Gerçek veritabanlarıyla çalışmaya başladığınızda, "Erken optimizasyon tüm kötülüklerin anasıdır" ifadesini hemen hatırlayacaksınız. Ancak şimdi onu olumsuz bir şekilde hatırlıyorsun. Bir veritabanı ile çalışırken, optimizasyon vazgeçilmezdir. Ve onunla zaten tasarım aşamasında çalışmanız gerekiyor.
Hazırda bekletme, veritabanıyla çalışmayı çok uygun hale getirir. Herhangi bir alt nesneyi yalnızca uygun şekilde açıklama ekleyerek kolayca elde edebilirsiniz @OneToMany
ve @ManyToMany
. Örnek:
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
public List<Comment> comments;
}
Ve kullanıcının yorumlarını almak ne kadar kolay:
User user = session.get(User.class, 1);
List<Comment> comments = user.getComments();
Ve sizi büyük bir sürpriz bekliyor olacak. Kullanıcının birkaç bin yorumu var. Bunun gibi bir kod yazarsanız, Hibernate elbette kullanıcının tüm yorumlarını yükleyecektir. Ancak çok yavaş olacak, yorumlar hafızada çok fazla yer kaplayacak vb.
Bu yüzden böyle yazamazsın! Teoride evet ama pratikte hayır.
1.2 Koleksiyonlarla işleri daha da kötüleştirmek
Sorun daha da ilginç. Sonuçta, genellikle hiçbir zaman tüm kullanıcı yorumlarına ihtiyacınız olmaz. İstemcide bir yerde görüntüleseniz bile, bunu parçalar - sayfalar halinde yapmayı tercih edersiniz.
Yani bunun gibi yöntemlere ihtiyacınız var:
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);
}
}
İlk yöntem yalnızca bir sayfa yorum döndürür - 50 parça. İkinci yöntem, yorumların sayfa sayısını döndürür. Ve bu en kötüsü. Sadece yorum sayısını öğrenmek için veritabanından tüm yorumları indirmeniz gerekiyordu!
1.3 Tünelin sonundaki ışık
Bu nedenle, harika çocuk koleksiyonlarımızı kimse kullanmıyor. Hayır, elbette kullanılırlar, ancak yalnızca HQL sorgularının bir parçası olarak kullanılırlar. Örneğin bunun gibi:
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);
}
}
İyi haber şu ki, yöntemlerimizi veritabanından fazladan veri yüklememize gerek kalmayacak şekilde uygulayabiliyoruz. Kötü haber şu ki koleksiyonlarımızla çalışmak kolay değil.