0

[Java Backend Zero to Hello] BÀI 5.4: SPRING DATA JPA

Java Backend Zero to Hello

📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 5: Spring Framework & Spring Boot | Bài 50/86


BÀI 5.4: SPRING DATA JPA

Mục tiêu

  • Sử dụng Spring Data JPA
  • Tạo Repository interface
  • Method naming convention
  • Custom query với @Query

1. SPRING DATA JPA LÀ GÌ?

Spring Data JPA là module của Spring Data, giúp đơn giản hóa việc truy cập database với JPA.

Lợi ích

  • Ít code boilerplate
  • Tự động generate query
  • Hỗ trợ pagination, sorting
  • Tích hợp với Spring Boot

2. DEPENDENCY

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

3. ENTITY

@Entity
@Table(name = "users")
@Data  // Lombok
@NoArgsConstructor
@AllArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 100)
    private String name;

    @Column(unique = true, nullable = false)
    private String email;

    private Integer age;

    @Column(name = "created_at", updatable = false)
    @CreationTimestamp
    private LocalDateTime createdAt;

    @UpdateTimestamp
    private LocalDateTime updatedAt;
}

4. REPOSITORY

4.1 JpaRepository

public interface UserRepository extends JpaRepository<User, Long> {
    // Tự động có sẵn:
    // save(), findById(), findAll(), deleteById(), count(), ...
}

4.2 CrudRepository

public interface UserRepository extends CrudRepository<User, Long> {
    // CRUD cơ bản
}

4.3 PagingAndSortingRepository

public interface UserRepository extends PagingAndSortingRepository<User, Long> {
    // Hỗ trợ pagination, sorting
}

4.4 Các method có sẵn

Method Mô tả
save(entity) Lưu (insert/update)
findById(id) Tìm theo ID
findAll() Lấy tất cả
findAllById(ids) Tìm theo nhiều ID
count() Đếm
existsById(id) Kiểm tra tồn tại
deleteById(id) Xóa theo ID
delete(entity) Xóa entity
deleteAll() Xóa tất cả

5. METHOD NAMING CONVENTION

Spring Data tự động generate query từ tên method.

5.1 Cú pháp

findBy + PropertyName + Condition + OrderBy + PropertyName + Direction

5.2 Ví dụ

public interface UserRepository extends JpaRepository<User, Long> {

    // Tìm theo field
    Optional<User> findByEmail(String email);

    List<User> findByName(String name);

    List<User> findByAge(Integer age);

    // Điều kiện
    List<User> findByAgeGreaterThan(Integer age);

    List<User> findByAgeLessThanEqual(Integer age);

    List<User> findByNameLike(String pattern);

    List<User> findByNameContaining(String keyword);

    List<User> findByNameStartingWith(String prefix);

    List<User> findByNameEndingWith(String suffix);

    List<User> findByAgeBetween(Integer min, Integer max);

    List<User> findByAgeIn(Collection<Integer> ages);

    List<User> findByNameIsNull();

    List<User> findByNameIsNotNull();

    // Boolean
    List<User> findByActiveTrue();

    List<User> findByActiveFalse();

    // Kết hợp AND/OR
    List<User> findByNameAndEmail(String name, String email);

    List<User> findByNameOrEmail(String name, String email);

    // Sắp xếp
    List<User> findByAgeOrderByNameAsc(Integer age);

    List<User> findByAgeOrderByNameDesc(Integer age);

    // Giới hạn
    List<User> findFirst10ByOrderByAgeDesc();

    User findFirstByOrderByCreatedAtDesc();

    // Đếm
    long countByAgeGreaterThan(Integer age);

    boolean existsByEmail(String email);

    // Xóa
    long deleteByAgeLessThan(Integer age);
}

5.3 Từ khóa hỗ trợ

Keyword SQL
Is, Equals =
Not <>
Like LIKE
Containing LIKE %x%
StartingWith LIKE x%
EndingWith LIKE %x
GreaterThan >
LessThan <
Between BETWEEN
In IN
IsNull IS NULL
IsNotNull IS NOT NULL
True = true
False = false
And AND
Or OR
OrderBy ORDER BY

6. @QUERY - CUSTOM QUERY

6.1 JPQL

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmailCustom(@Param("email") String email);

    @Query("SELECT u FROM User u WHERE u.age >= :minAge ORDER BY u.name")
    List<User> findAdults(@Param("minAge") int minAge);

    @Query("SELECT u.name, u.email FROM User u")
    List<Object[]> findNameAndEmail();

    @Query("SELECT new com.example.dto.UserDTO(u.name, u.email) FROM User u")
    List<UserDTO> findAllDTO();
}

6.2 Native Query

@Query(value = "SELECT * FROM users WHERE email = :email", nativeQuery = true)
Optional<User> findByEmailNative(@Param("email") String email);

6.3 Update Query

@Modifying
@Query("UPDATE User u SET u.name = :name WHERE u.id = :id")
int updateName(@Param("id") Long id, @Param("name") String name);

6.4 Delete Query

@Modifying
@Query("DELETE FROM User u WHERE u.age < :age")
int deleteOldUsers(@Param("age") int age);

7. PAGINATION

public interface UserRepository extends JpaRepository<User, Long> {

    Page<User> findByAgeGreaterThan(int age, Pageable pageable);

    Slice<User> findByNameContaining(String name, Pageable pageable);
}

Sử dụng

Pageable pageable = PageRequest.of(0, 10, Sort.by("name").ascending());
Page<User> page = userRepository.findByAgeGreaterThan(18, pageable);

List<User> content = page.getContent();
int totalPages = page.getTotalPages();
long totalElements = page.getTotalElements();
boolean hasNext = page.hasNext();

8. SORTING

List<User> findAll(Sort.by("name").ascending());
List<User> findAll(Sort.by(Sort.Order.asc("lastName"), Sort.Order.desc("firstName")));

9. CUSTOM REPOSITORY

9.1 Interface

public interface UserRepositoryCustom {
    List<User> findByCustomQuery();
}

9.2 Implementation

@Repository
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepositoryCustom {

    @PersistenceContext
    private EntityManager em;

    @Override
    public List<User> findByCustomQuery() {
        return em.createQuery("SELECT u FROM User u WHERE ...", User.class)
                 .getResultList();
    }
}

9.3 Kết hợp

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
}

10. SPECIFICATIONS (Dynamic Query)

public interface UserRepository extends JpaRepository<User, Long>,
                                        JpaSpecificationExecutor<User> {
}
public class UserSpecs {
    public static Specification<User> hasName(String name) {
        return (root, query, cb) ->
            name == null ? null : cb.like(root.get("name"), "%" + name + "%");
    }

    public static Specification<User> hasMinAge(Integer age) {
        return (root, query, cb) ->
            age == null ? null : cb.greaterThanOrEqualTo(root.get("age"), age);
    }
}

// Sử dụng
Specification<User> spec = Specification.where(hasName("An"))
    .and(hasMinAge(18));
List<User> users = userRepository.findAll(spec);

11. ENTITY GRAPH (Eager Loading)

@Entity
@NamedEntityGraph(name = "User.orders",
    attributeNodes = @NamedAttributeNode("orders"))
public class User {
    @OneToMany(mappedBy = "user")
    private List<Order> orders;
}
@EntityGraph(value = "User.orders")
Optional<User> findById(Long id);

12. AUDITING

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class Auditable {
    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String updatedBy;
}

Enable: @EnableJpaAuditing trên main class.


13. BÀI TẬP THỰC HÀNH

Bài 1: User Repository

Tạo UserRepository với:

  • findByEmail
  • findByAgeGreaterThan
  • existsByUsername
  • countByStatus

Bài 2: Custom Query

Viết query:

  • Tìm user có nhiều orders nhất
  • Tính tổng giá trị orders

Bài 3: Pagination

Implement API trả về user có phân trang.


14. TÓM TẮT

Khái niệm Mô tả
JpaRepository Interface chính
Method Naming Tự sinh query
@Query Custom JPQL/Native
Pageable Phân trang
Sort Sắp xếp
Specification Dynamic query
EntityGraph Eager loading
Auditing Tự động track

Bài tiếp theo: 5.5 Spring Web MVC


🧭 Điều Hướng Series

⬅️ Bài trước: BÀI 5.3: BEAN & DEPENDENCY INJECTION

📋 Lộ trình tổng quan: Xem Toàn Bộ Series

➡️ Bài tiếp theo: BÀI 5.5: SPRING WEB MVC


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí