Hướng dẫn annotation @Query / NativeQuery trong Spring data
Spring Data annotation @Query
Với annotation @Query
ta có thể khai báo câu query cho các method trong repository.
Việc khai báo câu query với @Query giúp ta tối ưu câu sql, và xử lý trong những trường hợp mà các method do Spring Data không thể đáp ứng:
- Việc sử dụng các method có sẵn khi extends interface
JPARepository
,CrudRepository
không đáp ứng được yêu cầu. - Việc đặt tên method theo chuẩn Query Creation quá dài hoặc tối nghĩa. (Ví dụ bạn muốn truy vấn theo 5 điều kiện thì tên method của bạn sẽ gồm 5 điều kiện đó => quá dài)
Sử dụng @Query
Để sử dụng annotation @Query, ta sẽ khai báo nó trước các method của interface extends từ JPARepository
, CrudRepository
, và truyền câu hsql vào bên trong
Ví dụ:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e ORDER BY e.name DESC")
- List<Customer> findAllOrderByNameDesc();
- }
Với trường hợp câu sql có tham số từ bên ngoài ta có 2 cách để truyền vào:
Cách 1: truyền theo thứ tự:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = ?1 AND e.address = ?2")
- List<Customer> findByNameAndAddress(String name, String address);
- }
Với cách này thứ tự các tham số của method phải giống với thứ tự các tham số truyền vào câu query
Cách 2: sử dụng annotation @Param
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = :name AND e.address = :address")
- List<Customer> findByNameAndAddress(@Param("name") String name, @Param("address") String address);
- }
Bản thân mình thấy cách này rõ ràng hơn, câu query vừa dễ đọc lại không lo nhầm thứ tự các tham số.
Kết quả trả về của method sử dụng @Query
Kết quả trả về của method sử dụng @Query có thể là:
Một List:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = :name")
- List<Customer> findByName(@Param("name") String name);
- }
Một Stream:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = :name")
- Stream<Customer> findByName(@Param("name") String name);
- }
Ta dùng stream cho những trường hợp kết quả của câu query có quá nhiều bản ghi, thay vì phải tạo rất nhiều đối tượng để lưu các bản ghi đó ta sẽ tạo ra 1 stream, và nó chỉ thực sự tạo ra các đối tượng khi bạn sử dụng đến phần tử bên trong stream.
Một Page:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = :name")
- Page<Customer> findByName(@Param("name") String name, Pageable pageable);
- }
(Việc trả về Page áp dụng cho trường hợp muốn phân trang, mình sẽ nói rõ hơn ở bài sau)
Một đối tượng:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query("SELECT e FROM Customer e WHERE e.name = :name")
- Customer findByName(@Param("name") String name);
- }
Ta chỉ sử dụng khi chắc chắn kết quả của câu query sẽ trả về 1 đối tượng, nếu câu query trả về nhiều hơn 1 đối tượng thì sẽ xảy ra lỗi.
Sử dụng NativeQuery
Để sử dụng native query ta sử dụng thuộc tính nativeQuery = true
bên trong annotation @Query
Ví dụ:
- @Repository
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
- @Query(value = "SELECT e.* FROM customer e ORDER BY e.name DESC", nativeQuery = true)
- List<Customer> findAllOrderByNameDesc();
- }
Okay, Done!
(Xem thêm code ví dụ Spring Boot Data JPA annotation @Query)
References: