Khi làm việc với Hibernate trong Spring boot, một trong những vấn đề phổ biến nhất mà các developer gặp phải là vấn đề N + 1 query. Vấn đề này không chỉ làm giảm performance của hệ thống mà còn gây ra các vấn đề khác liên quan tới tài nguyên của hệ thống.
1. N+1 Query là gì?
Vấn dề N+1 query xảy ra khi lấy dữ liệu từ cơ sở dữ liệu theo cách mà thay vì thực hiện một query duy nhất để lấy ra tất cả các dữ liệu cần thiết, hệ thống lại thực hiện N+1 query. Điều này thường xảy ra khi lấy một danh sách các đối tượng và sau đó lấy thuộc tính liên quan tới đối tượng trong danh sách đó.
Ví dụ, có 2 entities Author và Book, trong đó 1 Author có thể có nhiều Book. Nếu lấy danh sách các Author và lấy danh sách các Book thì có thể sẽ gặp vấn để N+1 query.
Ví dụ cụ thể
- 2 entity Author và Book
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private List<Book> books;
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne
@JoinColumn(name = "author_id")
private Author author;
}
- Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
}
- Service
@Service
public class AuthorService {
@Autowired
private AuthorRepository authorRepository;
public List<Author> getAllAuthors() {
return authorRepository.findAll();
}
}
- Controller
@RestController
@RequestMapping("/authors")
public class AuthorController {
@Autowired
private AuthorService authorService;
@GetMapping
public List<Author> getAllAuthors() {
return authorService.getAllAuthors();
}
}
Trong ví dụ trên, khi gọi API để get tất cả các Author, Hibernate sẽ thực hiện một câu truy vấn để lấy danh sách các Author. Sau đó, sẽ thực hiện N truy vấn để lấy danh sách Book cho từng Author
2. Cách giải quyết
- Để giải quyết vấn đề trên chúng ta có thể sử dụng JOIN FETCH để lấy toàn bộ data cần thiết trong cùng 1 câu query.
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Query("SELECT a FROM Author a JOIN FETCH a.books")
List<Author> findAllWithBooks();
}
- Ngoài ra có thể sử dụng nativeQuery thay vì sử dụng HQL để lấy dữ liệu
3. Kết luận
Vấn đề N+1 query là một vấn đề phổ biến nhưng có thể được giải quyết hiệu quả bằng cách sử dụng các kỹ thuật như JOIN FETCH trong Hibernate. Bằng cách hiểu rõ và áp dụng các kỹ thuật này, bạn có thể cải thiện hiệu suất của ứng dụng và tránh các vấn đề liên quan đến hiệu năng.
source: https://www.baeldung.com/spring-hibernate-n1-problem