Other Methods, Modifying Queries

2024. 10. 20. 19:18Spring Boot/Spring Data JPA

Other Methods

Spring Data JPA는 다양한 방법으로 쿼리를 작성할 수 있는 기능을 제공합니다. 그러나 때때로 쿼리가 제공된 기술로는 너무 복잡할 수 있습니다. 이런 경우에는 다음과 같은 대안들을 고려해볼 수 있습니다.

1. 직접 쿼리 작성하기

가장 먼저 고려해야 할 방법은 @Query 어노테이션을 사용하여 직접 쿼리를 작성하는 것입니다. 이를 통해 JPQL, HQL, 또는 네이티브 SQL을 사용하여 원하는 대로 쿼리를 구성할 수 있습니다.

예를 들어:

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("SELECT u FROM User u WHERE u.lastname = ?1")
  List<User> findByLastname(String lastname);
}

이와 같이 쿼리를 직접 작성하면, 쿼리가 복잡하더라도 원하는 결과를 얻을 수 있습니다.

2. 커스텀 구현체 만들기

직접 쿼리를 작성하는 것이 충분하지 않거나 더 복잡한 로직이 필요한 경우, 커스텀 구현을 고려할 수 있습니다. 이를 통해 레포지토리에 메서드를 등록하면서 구현은 전적으로 사용자에게 맡길 수 있습니다.

이렇게 하면 다음과 같은 기능을 활용할 수 있습니다:

  • EntityManager 직접 사용: 순수 HQL, JPQL, EQL, 네이티브 SQL을 작성하거나 Criteria API를 사용할 수 있습니다.
  • Spring Framework의 JdbcTemplate 활용: 네이티브 SQL을 작성하여 데이터베이스와 직접 상호작용할 수 있습니다.
  • 타사 데이터베이스 툴킷 사용: 특정 데이터베이스나 ORM에 특화된 툴킷을 사용할 수 있습니다.

예를 들어, 커스텀 리포지토리 구현을 통해 복잡한 쿼리를 작성할 수 있습니다:

public class UserRepositoryImpl implements UserRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<User> customQueryMethod() {
        String jpql = "SELECT u FROM User u WHERE u.age > :age";
        return entityManager.createQuery(jpql, User.class)
                            .setParameter("age", 18)
                            .getResultList();
    }
}

3. 데이터베이스 내장 쿼리 사용하기

쿼리를 데이터베이스에 저장하고 싶다면, @StoredProcedure 어노테이션을 사용하여 저장 프로시저를 호출하거나, 데이터베이스 함수에 대해 @Query 어노테이션을 사용하고 CALL로 호출할 수 있습니다.

예를 들어, 저장 프로시저를 호출하는 방법은 다음과 같습니다:

public interface UserRepository extends JpaRepository<User, Long> {

    @Modifying
    @Procedure(name = "my_procedure")
    void callMyProcedure();
}


이러한 방법들은 최대한의 쿼리 제어를 필요로 할 때 유용하며, Spring Data JPA가 제공하는 자원 관리 기능을 유지하면서도 더 복잡한 로직을 구현할 수 있게 해줍니다. 각 방법의 사용은 필요에 따라 선택할 수 있으며, 복잡한 쿼리 로직을 요구하는 비즈니스 요구사항에 맞게 조정할 수 있습니다.

Modifying Queries

Spring Data JPA는 쿼리를 선언하여 엔티티나 엔티티 컬렉션에 접근하는 방법을 설명했습니다. 이제는 쿼리를 수정하는 사용자 정의 동작을 추가할 수 있는 방법에 대해 알아보겠습니다.

1. 수정 쿼리 선언하기

수정 쿼리는 특정 엔티티의 속성을 업데이트하거나 삭제하는 쿼리입니다. 이를 위해 @Modifying 어노테이션을 사용해야 합니다. 다음은 수정 쿼리의 예시입니다:

@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

이와 같이 @Modifying을 사용하면 해당 쿼리가 선택 쿼리(selecting query)가 아닌 업데이트 쿼리로 처리됩니다.

2. EntityManager와의 관계

수정 쿼리를 실행한 후에는 EntityManager가 오래된 엔티티를 포함할 수 있습니다. Spring Data JPA는 EntityManager.clear()를 자동으로 호출하지 않습니다. 이는 여전히 플러시되지 않은 변경 사항을 모두 삭제하기 때문입니다. 만약 EntityManager를 자동으로 지우고 싶다면, @Modifying 어노테이션의 clearAutomatically 속성을 true로 설정할 수 있습니다.

3. 파생 삭제 쿼리

Spring Data JPA는 파생 삭제 쿼리를 지원하여 JPQL 쿼리를 명시적으로 선언하지 않고도 삭제 작업을 수행할 수 있습니다. 다음은 파생 삭제 쿼리의 예입니다:

interface UserRepository extends Repository<User, Long> {

  void deleteByRoleId(long roleId);

  @Modifying
  @Query("delete from User u where u.role.id = ?1")
  void deleteInBulkByRoleId(long roleId);
}

deleteByRoleId(long roleId) 메서드는 기본적으로 deleteInBulkByRoleId(long roleId)와 유사한 결과를 생성하는 것처럼 보입니다. 그러나 두 메서드 선언 사이에는 중요한 차이가 있습니다.

  • deleteInBulkByRoleId(...) 메서드는 주어진 JPQL 쿼리를 데이터베이스에 단일 쿼리로 발행합니다. 이로 인해 현재 로드된 User 인스턴스는 생명주기 콜백(lifecycle callbacks)을 호출하지 않습니다.
  • 반면에 deleteByRoleId(...)는 쿼리를 실행한 후 결과를 하나씩 삭제하여 영속성 제공자가 해당 엔티티에서 @PreRemove 콜백을 실제로 호출할 수 있도록 합니다.


파생 삭제 쿼리는 쿼리를 실행한 후 CrudRepository.delete(Iterable users) 메서드를 호출하여 엔티티를 삭제하는 방법의 단축키 역할을 합니다. 이를 통해 CRUD 연산의 일관성을 유지하면서 더 간결하게 쿼리를 작성할 수 있습니다. 수정 쿼리와 삭제 쿼리를 효과적으로 활용하면, 복잡한 비즈니스 로직을 간단하게 처리할 수 있습니다.

'Spring Boot > Spring Data JPA' 카테고리의 다른 글

Configuring Fetch- and LoadGraphs  (0) 2024.10.20
Applying Query Hints  (0) 2024.10.20
Using Sort, Scrolling Large Query Results  (0) 2024.10.20
Using @Query  (0) 2024.10.20
Using JPA Named Queries  (0) 2024.10.20