Hibernate dikembangkan dengan teknik Object-Relational-Mapping (ORM). Sisi lain Java Persistence API (JPA), mempunyai 2 metod yaitu LAZY dan EAGER (javax.persistence.FetchType). Ketika model ORM yang mempunyai relasi dengan model lain akan melakukan loading / fetching terhadap objek relasi tersebut. Disinilah peran fetch lazy dan eager akan penting. Artikel ini akan membahas apa itu fetch lazy dan eager, contoh code dalam project spring boot. Serta, kapan sebaiknya digunakan 2 tipe fetch ini.
Lazy
Apa itu
Lazy Fetch adalah strategi pengambilan data dalam Object-Relational Mapping (ORM) yang menunda pengambilan data terkait hingga data tersebut benar-benar diperlukan. Dalam konteks ORM seperti Hibernate yang digunakan bersama dengan Spring Boot, Lazy Fetch memungkinkan entitas terkait untuk tidak dimuat dari basis data sampai akses ke entitas tersebut dilakukan.
Kapan Lazy Fetch sebaiknya digunakan
Lazy Fetch sangat berguna ketika Anda memiliki relasi yang tidak selalu diperlukan dalam setiap operasi dan hanya diakses dalam situasi tertentu. Ini membantu mengurangi beban pada basis data dan meningkatkan efisiensi aplikasi secara keseluruhan. Namun, penting untuk memahami pola akses data Anda untuk menghindari masalah kinerja yang disebabkan oleh query tambahan yang tidak diinginkan.
Model dan Repository
Book.java
@Entity
@Data
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String ISBN;
private String title;
private Integer totalPage;
private String category;
@ManyToOne(fetch = FetchType.LAZY)
private Author author;
}
Author.java
@Entity
@Data
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String country;
}
BookRepository
@Repository
public interface BookRepository extends JpaRepository<Book, Long>{
@Query("select b from Book b left join fetch b.author where b.id = :id")
public Book getBookFetch(Long id);
}
Pada model Book terdapat relasi ke model Author, disitu tertulis @ManyToOne(fetch = FetchType.LAZY) menandakan pada saat process Fetch data ke Author menggunakan lazy.
Service
BookService.java
@Service
public class BookService {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
public Book get(Long bookId) {
return bookRepository.getReferenceById(bookId);
}
public void store(Book book) {
if(book.getAuthor() != null) {
authorRepository.save(book.getAuthor());
}
bookRepository.save(book);
}
}
LibraryService.java
@Service
public class LibraryService {
@Autowired
private BookRepository bookRepository;
public Book getBook(Long bookId) {
return bookRepository.findById(bookId).orElse(null);
}
public Book getBookFetch(Long bookId) {
return bookRepository.getBookFetch(bookId);
}
}
Pada libraryService terdapat 2 method yaitu getBook dan getBookFetch. Jika kita menggunakan getBook kemudian mengakses komponen didalamnya akan menyebabkan error LazyException. Untuk mengatasinya digunakan method getBookFetch, yang pada BookRepository melakukan query left join fetch ke Author. Untuk lebih jelas bisa perhatikan contoh di bawah.
Test dan Check Query yang terbentuk
jika kita menggunakan code ini
System.out.println("========= START LAZY ==========");
BookService bookService = applicationContext.getBean(BookService.class);
runBook(bookService);
LibraryService libraryService = applicationContext.getBean(LibraryService.class);
runLibrary(libraryService);
System.out.println("========= END LAZY ==========");
maka result yang terbentuk
========= START LAZY ==========
Hibernate:
insert
into
author
(country, name, id)
values
(?, ?, default)
Hibernate:
insert
into
book
(isbn, author_id, category, title, total_page, id)
values
(?, ?, ?, ?, ?, default)
Hibernate:
select
b1_0.id,
b1_0.isbn,
b1_0.author_id,
b1_0.category,
b1_0.title,
b1_0.total_page
from
book b1_0
where
b1_0.id=?
whoops could not initialize proxy [com.sufyan97.learn_hibernate.book.Author#1] - no Session
Hibernate:
select
b1_0.id,
b1_0.isbn,
a1_0.id,
a1_0.country,
a1_0.name,
b1_0.category,
b1_0.title,
b1_0.total_page
from
book b1_0
left join
author a1_0
on a1_0.id=b1_0.author_id
where
b1_0.id=?
J. K. Rowling
========= END LAZY ==========
Pembahasan Hasil
- Jika diperhatikan query yang terbentuk setelah insert hanya melakukan query pada tabel utama saja. Sehingga, memori yang digunakan jauh lebih hemat dan tidak terlalu membebani database.
- Ketika object relasi lazy diambil komponennya akan melempar error LazyInitializationException
- Untuk mengakalinya bisa digunakan query left join fetch seperti yang terbentuk pada method getBookFetch.
Eager
Apa itu
Eager Fetch adalah strategi pengambilan data dalam Object-Relational Mapping (ORM) di mana semua data yang terkait diambil sekaligus, bahkan jika data tersebut tidak segera diperlukan. Dalam konteks Hibernate dan Java Persistence API (JPA) yang digunakan bersama dengan Spring Boot, Eager Fetch memungkinkan entitas terkait untuk dimuat langsung saat entitas utama diambil dari basis data. Hal ini sangat berlawanan dengan Lazy Fetch yang tidak mengambil data relasinya.
Kapan Eager Fetch sebaiknya digunakan
Eager Fetch sangat berguna ketika Anda sering membutuhkan semua relasi saat mengakses entitas utama. Ini memastikan bahwa semua data yang diperlukan tersedia segera, mengurangi kebutuhan untuk query tambahan. Namun, ini harus digunakan dengan hati-hati untuk menghindari overfetching dan konsumsi memori yang berlebihan. Selain itu jika kita sangat "malas" berurusan dengan LazyInitializationException bisa gunakan cara ini. Selain itu query yang digunakan jauh lebih ringkas dibandingkan lazy fetch. Jika join data yang digunakan kecil juga lebih optimal dengan menggunakan Eager fetch.
Model dan Repository
Buku.java
@Entity
@Data
public class Buku {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String ISBN;
private String title;
private Integer totalPage;
private String category;
@ManyToOne(fetch = FetchType.EAGER)
private Penulis penulis;
}
Penulis.java
@Entity
@Data
public class Penulis {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String country;
}
BukuRepository.java
@Repository
public interface BukuRepository extends JpaRepository<Buku, Long>{
@Query("select b from Buku b left join fetch b.penulis where b.id = :id")
public Buku getBukuFetch(Long id);
}
Service
BukuService.java
@Service
public class BukuService {
@Autowired
public BukuRepository bukuRepository;
@Autowired
public PenulisRepository penulisRepository;
public Buku get(Long bookId) {
return bukuRepository.getReferenceById(bookId);
}
public void store(Buku buku) {
if(buku.getPenulis() != null) {
penulisRepository.save(buku.getPenulis());
}
bukuRepository.save(buku);
}
}
PerpustakaanService.java
@Service
public class PerpustakaanService {
@Autowired
public BukuRepository bukuRepository;
public Buku getBook(Long bookId) {
return bukuRepository.findById(bookId).orElse(null);
}
public Buku getBukuFetch(Long bookId) {
return bukuRepository.getBukuFetch(bookId);
}
}
Pada libraryService terdapat 2 method yaitu getBook dan getBookFetch. Jika kita menggunakan getBook kemudian mengakses komponen didalamnya akan menyebabkan error LazyException. Untuk mengatasinya digunakan method getBookFetch, yang pada BookRepository melakukan query left join fetch ke Author. Untuk lebih jelas bisa perhatikan contoh di bawah.
Test dan Check Query yang terbentuk
Jika digunakan baris kode ini untuk melakukan test
System.out.println("========= START EAGER ==========");
BukuService bukuService = applicationContext.getBean(BukuService.class);
runBuku(bukuService);
PerpustakaanService perpustakaanService = applicationContext.getBean(PerpustakaanService.class);
runPerpustakaan(perpustakaanService);
System.out.println("========= END EAGER ==========");
Maka akan menghasilkan
========= START EAGER ==========
Hibernate:
insert
into
penulis
(country, name, id)
values
(?, ?, default)
Hibernate:
insert
into
buku
(isbn, category, penulis_id, title, total_page, id)
values
(?, ?, ?, ?, ?, default)
Hibernate:
select
b1_0.id,
b1_0.isbn,
b1_0.category,
p1_0.id,
p1_0.country,
p1_0.name,
b1_0.title,
b1_0.total_page
from
buku b1_0
left join
penulis p1_0
on p1_0.id=b1_0.penulis_id
where
b1_0.id=?
Hibernate:
select
b1_0.id,
b1_0.isbn,
b1_0.category,
p1_0.id,
p1_0.country,
p1_0.name,
b1_0.title,
b1_0.total_page
from
buku b1_0
left join
penulis p1_0
on p1_0.id=b1_0.penulis_id
where
b1_0.id=?
J. K. Rowling
========= END EAGER ==========
Pembahasan hasil Eager
- Jika diperhatikan hasil query yang dihasilkan getBukuFetch dan getBook menghasilkan query yang sama.
- Ketika komponen object Penulis diambil tidak menyebabkan LazyInitializationException.
Sumber
- https://www.baeldung.com/hibernate-lazy-eager-loading diakses 22 Juni 2024
- https://www.geeksforgeeks.org/hibernate-eager-lazy-loading/ diakses 22 Juni 2024
- https://backendhance.com/en/blog/2023/jpa-fetching-strategies/ diakses 22 Juni 2024
Posting Komentar untuk "Spring boot Hibernate Basic 4 Memahami Lazy dan Eager Fetch dalam Spring Boot dan Hibernate"
Berilah komentar, saran, dan kritik dengan bijak