Bài 3: Repository Pattern trong Spring Data JPA
1. Giới thiệu về Repository Pattern
Repository Pattern là gì? Repository Pattern là một mẫu thiết kế phần mềm giúp tách biệt logic truy xuất dữ liệu ra khỏi logic nghiệp vụ của ứng dụng. Nó cung cấp một lớp trừu tượng giữa ứng dụng và cơ sở dữ liệu, cho phép chúng ta dễ dàng thực hiện các thao tác CRUD và các truy vấn phức tạp.
Lợi ích của việc sử dụng Repository Pattern
Đơn giản hóa mã nguồn: Giảm thiểu mã boilerplate cần viết khi thao tác với cơ sở dữ liệu.
Tái sử dụng mã nguồn: Dễ dàng tái sử dụng các phương thức truy xuất dữ liệu trong nhiều phần của ứng dụng.
Dễ dàng kiểm thử: Giúp tách biệt logic truy xuất dữ liệu, dễ dàng tạo các mock repository để kiểm thử.
Các loại repository trong Spring Data JPA
CrudRepository: Cung cấp các phương thức CRUD cơ bản.
PagingAndSortingRepository: Mở rộng CrudRepository, hỗ trợ thêm các phương thức phân trang và sắp xếp.
JpaRepository: Mở rộng PagingAndSortingRepository, cung cấp thêm các phương thức JPA-specific.
2. Tạo Repository cơ bản
Tạo interface Repository Để tạo một repository trong Spring Data JPA, chúng ta chỉ cần định nghĩa một interface và kế thừa từ một trong các interface repository của Spring Data JPA.
Ví dụ: Tạo 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> {
// Các phương thức truy vấn tùy chỉnh sẽ được định nghĩa ở đây
}
Trong ví dụ này, UserRepository kế thừa từ JpaRepository, do đó, nó sẽ tự động có các phương thức CRUD cơ bản và các phương thức phân trang, sắp xếp.
Các phương thức CRUD cơ bản Các phương thức CRUD cơ bản được cung cấp bởi JpaRepository bao gồm:
save(S entity): Lưu một entity vào cơ sở dữ liệu.findById(ID id): Tìm một entity theo ID.findAll(): Lấy tất cả các entity.deleteById(ID id): Xóa một entity theo ID.
Ví dụ cụ thể về sử dụng các phương thức CRUD cơ bản
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.repository.UserRepository;
import com.example.demo.entity.User;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User createUser(User user) {
return userRepository.save(user);
}
public User updateUser(Long id, User userDetails) {
User user = userRepository.findById(id).orElse(null);
if (user != null) {
user.setUsername(userDetails.getUsername());
user.setPassword(userDetails.getPassword());
return userRepository.save(user);
}
return null;
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
3. Custom query methods
Đị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ùy chỉnh chỉ 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.
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);
}
Trong ví dụ này:
findByUsername: Truy vấn tìm cácUsercóusernamelà giá trị được cung cấp.findByUsernameAndPassword: Truy vấn tìm cácUsercóusernamevàpasswordlà các giá trị được cung cấp.
Sử dụng annotation @Query để viết truy vấn HQL/JPQL Ngoài việc định nghĩa các phương thức truy vấn dựa trên tên phương thức, chúng ta còn có thể sử dụng annotation @Query để viết các truy vấn phức tạp hơ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("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);
}
Trong ví dụ này:
@Query: Được sử dụng để viết truy vấn HQL/JPQL tùy chỉnh.@Param: Được sử dụng để ánh xạ các tham số trong truy vấn với các tham số của phương thức.
4. Paging và Sorting
Sử dụng Pageable và Sort 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.
Ví dụ:
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);
}
Trong ví dụ này:
findByUsername: Truy vấn tìm cácUsercóusernamelà giá trị được cung cấp và trả về kết quả phân trang.
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.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);
}
}
Trong ví dụ này, phương thức getUsersByUsername sử dụng PageRequest để tạo một đối tượng Pageable với thông tin phân trang và sắp xếp.
Kết luận
Bài viết này đã giới thiệu về Repository Pattern trong Spring Data JPA, cách tạo và sử dụng các repository cơ bản, định nghĩa các phương thức truy vấn tùy chỉnh, và cách sử dụng phân trang và sắp xếp. Những kiến thức này là nền tảng quan trọng giúp bạn quản lý và truy xuất dữ liệu một cách hiệu quả trong các ứng dụng Spring Boot sử dụng Spring Data JPA. Các bài viết tiếp theo sẽ đi sâu vào các khía cạnh nâng cao hơn của Spring Data JPA như quản lý giao dịch, caching, và tối ưu hóa hiệu suất.