Bài 5: Query Methods và JPQL/HQL trong Spring Data JPA
1. Định nghĩa các phương thức truy vấn dựa trên tên phương thức
Spring Data JPA cung cấp khả năng tạo các phương thức truy vấn tự động bằng cách định nghĩa tên phương thức theo các quy tắc đặt tên nhất định.
Quy tắc đặt tên phương thức Spring Data JPA sử dụng một bộ quy tắc đặt tên phương thức để tự động tạo các truy vấn. Các quy tắc này bao gồm:
findBy: Truy vấn dựa trên các thuộc tính của entity.
countBy: Đếm số lượng entity thỏa mãn điều kiện.
deleteBy: Xóa các entity thỏa mãn điều kiện.
existsBy: Kiểm tra sự tồn tại của các entity thỏa mãn điều kiện.
Ví dụ:
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.User;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsername(String username);
List<User> findByUsernameAndPassword(String username, String password);
List<User> findByUsernameOrPassword(String username, String password);
Long countByUsername(String username);
void deleteByUsername(String username);
boolean existsByUsername(String username);
}
Giải thích các phương thức:
findByUsername: Truy vấn cácUsercó thuộc tínhusernamelà giá trị được cung cấp.findByUsernameAndPassword: Truy vấn cácUsercó thuộc tínhusernamevàpasswordlà các giá trị được cung cấp.findByUsernameOrPassword: Truy vấn cácUsercó thuộc tínhusernamehoặcpasswordlà các giá trị được cung cấp.countByUsername: Đếm số lượngUsercó thuộc tínhusernamelà giá trị được cung cấp.deleteByUsername: Xóa cácUsercó thuộc tínhusernamelà giá trị được cung cấp.existsByUsername: Kiểm tra sự tồn tại của cácUsercó thuộc tínhusernamelà giá trị được cung cấp.
2. Sử dụng JPQL/HQL trong Spring Data JPA
JPQL (Java Persistence Query Language) và HQL (Hibernate Query Language) là các ngôn ngữ truy vấn hướng đối tượng, cho phép chúng ta viết các truy vấn trên các entity thay vì các bảng cơ sở dữ liệu.
Sử dụng annotation @Query để viết truy vấn JPQL/HQL Annotation @Query trong Spring Data JPA cho phép chúng ta viết các truy vấn JPQL/HQL tùy chỉnh.
Ví dụ:
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.example.demo.entity.User;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.username = :username")
List<User> findByUsernameCustom(@Param("username") String username);
@Query("SELECT u FROM User u WHERE u.username = :username AND u.password = :password")
List<User> findByUsernameAndPasswordCustom(@Param("username") String username, @Param("password") String password);
@Query("SELECT COUNT(u) FROM User u WHERE u.username = :username")
Long countByUsernameCustom(@Param("username") String username);
}
Giải thích các truy vấn:
findByUsernameCustom: Truy vấn cácUsercó thuộc tínhusernamelà giá trị được cung cấp.findByUsernameAndPasswordCustom: Truy vấn cácUsercó thuộc tínhusernamevàpasswordlà các giá trị được cung cấp.countByUsernameCustom: Đếm số lượngUsercó thuộc tínhusernamelà giá trị được cung cấp.
3. Native Queries
Native Queries là các truy vấn SQL thuần, cho phép chúng ta viết các truy vấn SQL phức tạp mà JPQL/HQL không thể hỗ trợ.
Sử dụng annotation @Query với thuộc tính nativeQuery Annotation @Query với thuộc tính nativeQuery cho phép chúng ta viết các truy vấn SQL thuần.
Ví dụ:
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.example.demo.entity.User;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM users WHERE username = :username", nativeQuery = true)
List<User> findByUsernameNative(@Param("username") String username);
@Query(value = "SELECT * FROM users WHERE username = :username AND password = :password", nativeQuery = true)
List<User> findByUsernameAndPasswordNative(@Param("username") String username, @Param("password") String password);
@Query(value = "SELECT COUNT(*) FROM users WHERE username = :username", nativeQuery = true)
Long countByUsernameNative(@Param("username") String username);
}
Giải thích các truy vấn:
findByUsernameNative: Truy vấn cácUsercó thuộc tínhusernamelà giá trị được cung cấp sử dụng SQL thuần.findByUsernameAndPasswordNative: Truy vấn cácUsercó thuộc tínhusernamevàpasswordlà các giá trị được cung cấp sử dụng SQL thuần.countByUsernameNative: Đếm số lượngUsercó thuộc tínhusernamelà giá trị được cung cấp sử dụng SQL thuần.
4. Sử dụng EntityManager để thực thi các truy vấn tùy chỉnh
EntityManager là gì? EntityManager là một API cung cấp bởi JPA để quản lý các entity và thực hiện các truy vấn tùy chỉnh. Nó cho phép chúng ta thực hiện các truy vấn phức tạp mà Spring Data JPA không thể hỗ trợ.
Ví dụ sử dụng EntityManager
package com.example.demo.repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.User;
import java.util.List;
@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> findUsersWithCustomQuery(String username) {
TypedQuery<User> query = entityManager.createQuery("SELECT u FROM User u WHERE u.username = :username", User.class);
query.setParameter("username", username);
return query.getResultList();
}
}
Interface UserRepositoryCustom
package com.example.demo.repository;
import com.example.demo.entity.User;
import java.util.List;
public interface UserRepositoryCustom {
List<User> findUsersWithCustomQuery(String username);
}
Kết hợp UserRepositoryCustom với UserRepository
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.User;
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
// Các phương thức truy vấn tùy chỉnh sẽ được định nghĩa ở đây
}
5. Paging và Sorting
Spring Data JPA hỗ trợ phân trang và sắp xếp một cách dễ dàng thông qua các interface Pageable và Sort.
Sử dụng Pageable và Sort
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.example.demo.entity.User;
public interface UserRepository extends JpaRepository<User, Long> {
Page<User> findByUsername(String username, Pageable pageable);
}
Ví dụ cụ thể về sử dụng phân trang và sắp xếp trong service
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import com.example.demo.repository.UserRepository;
import com.example.demo.entity.User;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Page<User> getUsersByUsername(String username, int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("username").ascending());
return userRepository.findByUsername(username, pageable);
}
}
Controller sử dụng phân trang và sắp xếp
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public Page<User> getUsersByUsername(@RequestParam String username, @RequestParam int page, @RequestParam int size) {
return userService.getUsersByUsername(username, page, size);
}
}
Kết luận
Bài viết này đã giới thiệu chi tiết về cách định nghĩa các
phương thức truy vấn trong Spring Data JPA, sử dụng JPQL/HQL, Native Queries, và EntityManager để thực hiện các truy vấn tùy chỉnh, cũng như cách sử dụng phân trang và sắp xếp. Những kiến thức này sẽ giúp bạn xây dựng các ứng dụng Spring Boot với khả năng truy xuất và quản lý dữ liệu mạnh mẽ, linh hoạt. Các bài viết tiếp theo sẽ tiếp tục đi sâu vào các khía cạnh nâng cao hơn của Spring Data JPA như caching, tối ưu hóa hiệu suất, và xử lý các vấn đề phổ biến.