자바 웹 Query

Dear·2025년 7월 3일

TIL

목록 보기
54/74

💙 쿼리 메소드 (Query Method)

메소드 이름만으로 쿼리를 자동 생성해주는 기능

SQL이나 JPQL을 직접 작성하지 않아도, 정해진 네이밍 규칙대로 메소드를 작성하면 Spring이 알아서 쿼리를 만들어준다.

List<User> findByUsername(String username); 를 작성하면 Spring Data JPA는 자동으로
SELECT u FROM User u WHERE u.username = :username JPQL을 생성한다.

규칙

findBy | 필드명 | [조건]

메서드 이름생성되는 쿼리
findByUsername(String name)WHERE username = ?
findByEmailAndStatus(String e, String s)WHERE email = ? AND status = ?
findByAgeGreaterThan(int age)WHERE age > ?
findByCreatedAtBetween(start, end)WHERE created_at BETWEEN ? AND ?

사용 가능한 키워드 일부

키워드의미
And, Or논리 조건 연결
Between범위 조회
LessThan, GreaterThan<, > 비교
Like, Containing, StartingWith, EndingWith문자열 검색
In, NotIn목록 포함 여부
IsNull, IsNotNullnull 체크
OrderBy정렬 조건
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByAgeGreaterThan(int age);
    User findByEmailAndStatus(String email, String status);
    List<User> findByNameContaining(String keyword);
    List<User> findTop3ByOrderByCreatedAtDesc();
}

장점

  • 간단한 쿼리는 메소드 이름만으로 처리 가능
  • SQL/JPQL 작성 없이도 CRUD 이상 구현 가능
  • 실수할 여지가 줄어듦

단점

  • 복잡한 조건이 많이질수록 메소드명이 길고 복잡해짐
  • 복잡한 쿼리는 @Query나 Querydsl 사용 권장

💙 @Query

Spring Data JPA에서 쿼리를 직접 작성하고 싶을 때 사용하는 어노테이션

복잡한 조건이나 조인 등은 메소드 이름만으로 표현하기 어렵기 때문에 @Query를 사용해 직접 JPQL 또는 SQL을 작성한다.

@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);

SELECT u FROM User u... → JPQL (엔티티 기준의 쿼리)
:username → 파라미터 바인딩

// JPQL
@Query("SELECT u FROM User u WHERE u.age >= :age")
List<User> findUsersOlderThan(@Param("age") int age);

// 네이티브 SQL
@Query(value = "SELECT * FROM users WHERE email = :email", nativeQuery = true)
User findByEmailNative(@Param("email") String email);

// LIKE 검색
@Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
List<User> searchByName(@Param("name") String name);

수정 쿼리 (@Modifying)

데이터를 수정하거나 삭제할 경우 @Modifying과 함께 사용한다.

@Modifying
@Query("UPDATE User u SET u.status = 'INACTIVE' WHERE u.lastLogin < :date")
int deactivateOldUsers(@Param("date") LocalDate date);

이 경우 트랜잭션 처리를 위해 @Transactional도 함께 붙이거나, 서비스에서 트랜잭션을 관리해야한다.

💙 Querydsl

자바 코드로 SQL처럼 타입 안정성 있는 쿼리를 작성할 수 있게 해주는 프레임워크
Spring Data JPA와 함꼐 사용되며, 복잡한 조건 쿼리를 안전하고 깔끔하게 처리한다.

기존의 JPQL이나 @Query는 문자열 기반이라 컴파일 시점에 오류를 잡을 수 없지만, Querydsl은 자바 코드로 작성되므로 컴파일 타임에 오류를 잡을 수 있고 IDE 자동완성도 지원한다.

사용 흐름

  1. 의존선 추가(Gradle)
  2. Q클래스 생성
    빌드 시 자동 생성(QUser.java, QOrder.java 등)
  3. JPAQueryFactory 주입 후 사용

@RequiredArgsConstructor
@Repository
public class UserQueryRepository {

    private final JPAQueryFactory queryFactory;

    public List<User> findByName(String name) {
        QUser user = QUser.user;

        return queryFactory
                .selectFrom(user)
                .where(user.name.eq(name))
                .fetch();
    }
}

// 일반 JPQL
@Query("SELECT u FROM User u WHERE u.age > :age")
List<User> findByAgeGreaterThan(@Param("age") int age);

// Querydsl
// QUser는 Querydsl이 User 엔티티로부터 자동 생성한 클래스 
QUser user = QUser.user;

List<User> result = queryFactory
	.selectFrom(user)
    .where(user.age.gt(20))
    .fetch();
    

구성 요소

  • Q타입 클래스 : 엔티티를 기반으로 생성된 쿼리 전용 클래스 (ex: QUser)
  • JPAQueryFactory : 쿼리 생성을 위한 핵심 클래스
  • .select(), .from(), .where() : SQL 유사한 문법으로 조건 설정
  • .fetch() : 리스트 결과 반환, .fetchOne() 은 단일 결과

장점

  • 타입 안정성 : 컴파일 타임에 오류 검출 가능
  • 가독성 : SQL가 유사한 구조, 코드 기반 쿼리
  • 동적 쿼리 : 조건이 있을 때만 where()에 포함 가능
  • 자동완성 지원 : IDE 도움으로 개발 속도 향상

단점

  • 초기 설정이 다소 복잡 : 빌드 설정, Q 클래스 생성 필요
  • 러닝 커브 : JPA보다 문법이 많아 익숙해지는 데 시간 필요

💙 타임리프

HTML을 기반으로 한 서버 사이드 템플릿 엔진

HTML, XML, JavaScript, CSS, 텍스트 등을 렌더링할 수 있는 템플릿 엔진으로, HTML 파일 안에 특별한 속성(attribute)이나 문법을 삽입해서 동적으로 데이터를 출력할 수 있다.

  • 서버사이드 렌더링
    HTML에 데이터를 삽입해 완성된 HTML을 생성하여 클라이언트에 전달
    Controller -> HTML에 데이터를 삽입
  • 순수 HTML 파일로 사용 가능
    브라우저에서도 바로 열어볼 수 있는 형태의 HTML 사용 가능 ("Natural Template")
  • Spring과 강력한 통합
    Spring MVC 모델 객체를 쉽게 템플릿에 반영 가능 (th:each, th:text 등)
    - 표준 HTML5 지원
    HTML 태그와 속성을 그대로 유지하며 추가 속성으로 동작
  • 표현식 중심
    ${ }, th:text, th:if, th:each 등을 사용한 데이터 바인딩
  • JSP와 달리 컴파일러가 필요 없음
    템플릿 파일만으로 표현 가능
<!-- 변수 출력 -->
<p th:text="${name}">홍길동</p>  <!-- name 변수가 가진 값 출력 -->

<!-- 조건문 -->
<p th:if="${age > 18}">성인입니다</p>

<!-- 반복문 -->
<ul>
  <li th:each="item : ${itemList}" th:text="${item.name}"></li>
</ul>

<!-- 링크 처리 -->
<a th:href="@{/user/{id}(id=${user.id})}">프로필 보기</a>
속성설명
th:text텍스트 출력 (HTML 이스케이프됨)
th:utext텍스트 출력 (HTML 이스케이프 안 함)
th:if / th:unless조건문
th:each반복문
th:href / th:src링크, 이미지 경로 바인딩
th:object, *{}폼 바인딩에 사용

JSP와 차이점

항목JSPThymeleaf
문법Java 코드 삽입 가능 (<%= %>)HTML에 속성 방식으로 데이터 바인딩 (th:*)
디자인 확인브라우저에서 직접 보기 어려움HTML만으로 디자인 확인 가능
설정 복잡성톰캣 + JSP 설정 필요Spring Boot에서 바로 사용 가능
학습 난이도Java와의 혼합 문법HTML 친화적 문법
레이아웃 재사용JSP include 태그 사용th:replace, th:fragment 등 유연한 구조 사용

🤍 회고

오늘은 스프링에서의 쿼리 사용법과 타임리프에 대해 공부했다.
Querydsl은 조건이 많거나 동적으로 쿼리가 달라지는 경우에 유용하며, 성능 최적화를 위한 세밀한 쿼리 제어가 가능하다. 또한 타입 안정성과 자동완성 기능을 제공해 복잡한 쿼리를 안정적으로 작성할 수 있다.

타임리프는 정적 HTML 파일로도 열람이 가능해 템플릿 미리보기에 유리하며, 스프링 MVC와의 통합이 자연스럽다. 표현 방식이 직관적이고 읽기 쉬워 EL 표현식보다 가독성이 좋으며, Spring Form과 연동되어 폼 입력 처리에도 적합하다.

profile
친애하는 개발자

0개의 댓글