1.1 ความเป็นมาของปัญหา
เมื่อคุณเริ่มทำงานกับฐานข้อมูลจริง คุณจะจำวลีที่ว่า “การเพิ่มประสิทธิภาพก่อนเวลาอันควรเป็นรากเหง้าของความชั่วร้ายทั้งหมด” ตอนนี้คุณจำเธอในทางลบเท่านั้น เมื่อทำงานกับฐานข้อมูล การเพิ่มประสิทธิภาพเป็นสิ่งที่ขาดไม่ได้ และคุณต้องทำงานกับมันในขั้นตอนการออกแบบ
ไฮเบอร์เนตทำให้การทำงานกับฐานข้อมูลสะดวกมาก คุณสามารถรับออบเจกต์ย่อยใดๆ ได้ง่ายๆ เพียงแค่ใส่คำอธิบายประกอบอย่างถูกต้อง@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);
}
}
วิธีแรกส่งคืนความคิดเห็นเพียงหน้าเดียว - 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);
}
}
ข่าวดีก็คือ เราสามารถใช้วิธีการของเราในลักษณะที่เราไม่ต้องโหลดข้อมูลเพิ่มเติมจากฐานข้อมูล ข่าวร้ายก็คือ มันไม่ง่ายเลยที่จะทำงานกับคอลเลกชันของเรา