การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน
ส่งคืนผลลัพธ์แบบแบ่งหน้าด้วย Pageable เรียงลำดับแบบไดนามิก และใช้โปรเจกชันของ interface เพื่อลดคอลัมน์ที่ดึงมา
การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องแบ่งหน้า
การส่งคืนแถวหลายพันรายการด้วยคิวรีเดียวทำให้สิ้นเปลืองหน่วยความจำและแบนด์วิดท์ การแบ่งหน้าจะโหลดข้อมูลทีละหน้า และ Spring Data รองรับการแบ่งหน้าผ่านสิ่งนามธรรม Pageable
การแบ่งหน้าและคำขอหน้า
สร้าง Pageable ด้วย PageRequest.of(page, size) แล้วส่งไปยังเมธอดของรีโพซิทอรีที่ส่งคืน Page<T>
Pageable pageable = PageRequest.of(0, 20); // page 0, 20 per page
Page<User> page = userRepo.findAll(pageable);
System.out.println("Total: " + page.getTotalElements());
System.out.println("Pages: " + page.getTotalPages());
System.out.println("Content: " + page.getContent().size());การเรียงลำดับด้วยคำขอหน้า
เพิ่มการเรียงลำดับให้กับ PageRequest ด้วยออบเจ็กต์ Sort และเชื่อมหลายฟิลด์เข้าด้วยกันด้วย Sort.by().and()
Pageable sorted = PageRequest.of(0, 20,
Sort.by(Sort.Direction.DESC, "createdAt")
.and(Sort.by("name")));
Page<User> page = userRepo.findAll(sorted);ส่วนข้อมูลเทียบกับหน้า
Page<T> จะทำคิวรี COUNT เพื่อคำนวณจำนวนหน้าทั้งหมด ส่วน Slice<T> จะไม่ทำเช่นนั้น แต่จะทราบเพียงว่ามีหน้าถัดไปหรือไม่ ใช้ Slice กับการเลื่อนดูข้อมูลแบบไม่สิ้นสุดเมื่อไม่จำเป็นต้องทราบจำนวนทั้งหมด
public interface UserRepository extends JpaRepository<User, Long> {
Slice<User> findByStatus(UserStatus status, Pageable pageable);
}การผสานรวมกับสปริง เอ็มวีซี
สปริง เอ็มวีซีจะแปลงพารามิเตอร์คิวรีเป็น Pageable โดยอัตโนมัติ: ?page=0&size=20&sort=name,asc จึงไม่จำเป็นต้องแยกวิเคราะห์ด้วยตนเอง
@GetMapping("/users")
public Page<UserDto> list(Pageable pageable) {
return userRepo.findAll(pageable).map(UserDto::from);
}
// GET /users?page=0&size=10&sort=name,ascการฉายข้อมูลด้วยอินเทอร์เฟซ
กำหนดอินเทอร์เฟซที่มีเมธอดสำหรับอ่านค่าซึ่งตรงกับชื่อฟิลด์ของเอนทิตี สปริง ดาตาจะส่งคืนเฉพาะคอลัมน์เหล่านั้น จึงช่วยลดการถ่ายโอนข้อมูลและซ่อนรายละเอียดภายใน
public interface UserSummary {
Long getId();
String getName();
String getEmail();
}
List<UserSummary> findByStatus(UserStatus status);การฉายข้อมูลด้วยคลาส (ออบเจ็กต์ถ่ายโอนข้อมูล)
ใช้เรกคอร์ดหรือคลาสสำหรับถ่ายโอนข้อมูลที่มีตัวสร้าง สปริง ดาตาจะสร้างนิพจน์ตัวสร้างของ JPQL สำหรับคอลัมน์ที่เลือกโดยอัตโนมัติ
public record UserDto(Long id, String name, String email) {}
@Query("SELECT new com.example.UserDto(u.id, u.name, u.email) FROM User u WHERE u.status = :s")
List<UserDto> findSummaries(@Param("s") UserStatus status);การฉายข้อมูลแบบไดนามิก
ส่งชนิดของการฉายข้อมูลเป็นพารามิเตอร์ชนิดทั่วไปให้กับเมธอดของรีโพซิทอรี เพื่อเลือกการฉายข้อมูล ณ จุดที่เรียกใช้เมธอด
public interface UserRepository extends JpaRepository<User, Long> {
<T> List<T> findByStatus(UserStatus status, Class<T> type);
}
// Usage:
List<UserSummary> summaries = repo.findByStatus(ACTIVE, UserSummary.class);
List<User> full = repo.findByStatus(ACTIVE, User.class);การแบ่งหน้าแบบคีย์เซ็ต (ออฟเซ็ตเทียบกับคีย์เซ็ต)
การแบ่งหน้าแบบออฟเซ็ต (OFFSET N) จะทำงานช้าลงเมื่อออฟเซ็ตมีค่ามาก การแบ่งหน้าแบบคีย์เซ็ต (โดยใช้ WHERE id > lastSeenId) มีความซับซ้อน O(1) ไม่ว่าความลึกของหน้าจะเป็นเท่าใด จึงเหมาะกว่าสำหรับการแบ่งหน้าไปยังหน้าลึก ๆ
// Keyset pagination:
@Query("SELECT u FROM User u WHERE u.id > :lastId ORDER BY u.id LIMIT :size")
List<User> findPage(@Param("lastId") Long lastId, @Param("size") int size);การปรับปรุงประสิทธิภาพการนับทั้งหมด
ใช้ countQuery ใน @Query เพื่อระบุคิวรีนับจำนวนที่ปรับให้มีประสิทธิภาพ ซึ่งช่วยหลีกเลี่ยงการเชื่อมตารางที่มีค่าใช้จ่ายสูงจากคิวรีหลัก
@Query(value = "SELECT u FROM User u JOIN FETCH u.orders WHERE u.status = :s",
countQuery = "SELECT COUNT(u) FROM User u WHERE u.status = :s")
Page<User> findActiveWithOrders(@Param("s") UserStatus s, Pageable p);การส่งคืน ResponseEntity พร้อมข้อมูลเมตาของหน้า
ใส่ข้อมูลเมตาของหน้า (totalElements, totalPages, หมายเลขหน้า, ขนาดหน้า) ไว้ในการตอบกลับ REST เพื่อให้ไคลเอ็นต์ทราบวิธีเลื่อนไปยังหน้าต่าง ๆ
@GetMapping("/users")
public ResponseEntity<Map<String, Object>> list(Pageable p) {
Page<UserDto> page = repo.findAll(p).map(UserDto::from);
return ResponseEntity.ok(Map.of(
"content", page.getContent(),
"totalElements", page.getTotalElements(),
"totalPages", page.getTotalPages()
));
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
ความแตกต่างสำคัญระหว่าง Page กับส่วนข้อมูลคืออะไร
สรุปทบทวน
ใช้ Pageable+PageRequest.of() สำหรับการแบ่งหน้าแบบออฟเซ็ต สปริง เอ็มวีซีจะแปลงพารามิเตอร์คิวรีเป็น Pageable ใช้ Slice เพื่อหลีกเลี่ยง COUNT ใช้การฉายข้อมูลด้วยอินเทอร์เฟซหรือออบเจ็กต์ถ่ายโอนข้อมูลเพื่อจำกัดคอลัมน์ที่โหลด และใช้การแบ่งหน้าแบบคีย์เซ็ตเมื่อออฟเซ็ตมีค่ามาก
คำถามที่พบบ่อย
บทเรียน “การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน”
ส่งคืนผลลัพธ์แบบแบ่งหน้าด้วย Pageable เรียงลำดับแบบไดนามิก และใช้โปรเจกชันของ interface เพื่อลดคอลัมน์ที่ดึงมา คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การแมปเอนทิตีด้วยคำอธิบาย JPA
- รีโพซิทอรี Spring Data และเมธอดค้นหา
- ความสัมพันธ์แบบหนึ่งต่อกลุ่มและกลุ่มต่อกลุ่ม
- การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน