0Pricing
Java Academy · บทเรียน

การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน

ส่งคืนผลลัพธ์แบบแบ่งหน้าด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การแมปเอนทิตีด้วยคำอธิบาย JPA
  2. รีโพซิทอรี Spring Data และเมธอดค้นหา
  3. ความสัมพันธ์แบบหนึ่งต่อกลุ่มและกลุ่มต่อกลุ่ม
  4. การแบ่งหน้า การเรียงลำดับ และโปรเจกชัน
← กลับไปที่ Java Academy