24.10.02

윤지현·2024년 10월 4일

TIL

목록 보기
72/75

QueryDSL이란?

QueryDSL 소개

  • Entity 의 매핑정보를 활용하여 쿼리에 적합하도록 쿼리 전용 클래스(Q클래스)로 재구성해주는 기술
  • 여기에 JPAQueryFactory 을 통한 Q클래스를 활용할 수 있는 기능들을 제공
  • 그럼, JPAQueryFactory 는 뭘까?
    • 재구성한 Q클래스를 통해 문자열이 아닌 객체 또는 함수로 쿼리를 작성하고 실행하게 해주는 기술

@PersistenceContext
EntityManager em;
public List<User> selectUserByUsernameAndPassword(String username, String password){
	JPAQueryFactory jqf = new JPAQueryFactory(em);
	QUser user = QUser.user;
	List<Person> userList = jpf
								.selectFrom(user)								.where(person.username.eq(username)								.and(person.password.eq(password))
								.fetch();                              
	return userList;
}

이번에 getTodo메서드에서 findByIdWithUser를 QueryDSL로 변경했다.

public TodoResponse getTodo(long todoId) {
        Todo todo = todoRepository.findByIdWithUser(todoId)
                .orElseThrow(() -> new InvalidRequestException("Todo not found"));

        User user = todo.getUser();

        return new TodoResponse(
                todo.getId(),
                todo.getTitle(),
                todo.getContents(),
                todo.getWeather(),
                new UserResponse(user.getId(), user.getEmail()),
                todo.getCreatedAt(),
                todo.getModifiedAt()
        );
    }

1. TodoRepositoryQuery 인터페이스
QueryDSL 메서드를 정의하는 인터페이스를 만들었다.

public interface TodoRepositoryQuery {

    Optional<Todo> findByIdWithUser(Long todoId);
}

2. TodoRepositoryQueryImpl 클래스
QueryDSL을 이용하여 메서드를 구현

@RequiredArgsConstructor
public class TodoRepositoryQueryImpl implements TodoRepositoryQuery{

    private final JPAQueryFactory jpaQueryFactory;

    @Override
    public Optional<Todo> findByIdWithUser(Long todoId) {
        QTodo todo = QTodo.todo;
        Todo result = jpaQueryFactory
                .selectFrom(todo)
                .leftJoin(todo.user).fetchJoin() // N+1 문제 해결
                .where(todo.id.eq(todoId))
                .fetchOne();

        return Optional.ofNullable(result);
    }
}

3. TodoRepository 인터페이스
기본 CRUD 메소드가 포함된 TodoRepository에 QueryDSL을 정의한 TodoRepositoryQuery도 포함

public interface TodoRepository extends JpaRepository<Todo, Long>, TodoRepositoryQuery {
}

그러면 쿼리가 이렇게 join fetch되어서 N+1문제도 해결된채 잘 나오게 된다.

Hibernate: 
    /* select
        todo 
    from
        Todo todo   
    left join
        
    fetch
        todo.user 
    where
        todo.id = ?1 */ select
            t1_0.id,
            t1_0.contents,
            t1_0.created_at,
            t1_0.modified_at,
            t1_0.title,
            t1_0.user_id,
            u1_0.id,
            u1_0.created_at,
            u1_0.email,
            u1_0.modified_at,
            u1_0.nickname,
            u1_0.password,
            u1_0.user_role,
            t1_0.weather 
        from
            todos t1_0 
        left join
            users u1_0 
                on u1_0.id=t1_0.user_id 
        where
            t1_0.id=?

profile
첫 시작

0개의 댓글