JPA - JPQL

TopOfTheHead·2026년 4월 26일

MyBatis / JPA

목록 보기
8/10

JPQL ( Java Persistence Query Language )
。특정 DB에 종속되지 않는 Entity 중심의 객체지향 쿼리 언어

JPA의 일부로서 DB Table이 아닌 영속성 컨텍스트DB Entity를 대상으로 SQL Query를 작성
Native SQL과 거의 동일하나, Entity Class를 기준으로 컴파일러의 도움을 받을 수 있다.

。간단하게 Query를 정의하여 CRUD를 수행 시 주로 사용하는 방식
▶ 복잡한 Query의 경우 MyBatis 등을 사용.


JPQL 특징

  • JPQL조회에 특화된 쿼리로서 쓰기 작업에는 비효율적
    。보통 조회 시에 JPQL을 사용하고, 쓰기 작업의 경우 EntityManager.persist()를 활용해서 영속성 컨텍스트영속화작업을 수행
    QueryDSLJPQL을 생성하는 기능이므로, 마찬가지로 조회 목적으로만 사용

    JPQL쓰기 작업 자체는 가능하지만, EntityManager 방식에 비해 비효율적이므로 권고하지는 않는다.

  • JPQL 문을 작성 시 EntityAlias를 지정하여 Query를 작성
    DB Table명으로 Query하는게 아닌 DB Entity명으로 Query를 수행
        SELECT
            m.id,
            m.name,
            m.password,
            m.email,
            m.balance
        FROM Member m

DB Table컬럼이 아닌, Entity Class필드를 기준으로 조회

  • JPQL인자 전달매개변수로 입력 시 순서대로 JPQL?1, ?2 ...으로 전달
    。 또는 WHERE m.loginId = :loginId:매개변수명으로 직접 명시적으로 할당가능

  • JPQL그래프 탐색
    JPQL에서 Entity 클래스연관관계 Entity 필드를 기반으로 조건 설정 시 다음처럼 엔티티별칭.연관관계Entity.필드참조
    ▶ 해당 연관관계 Entity그래프 자료구조 탐색처럼 탐색을 수행하여 참조
	@Query(
            value = """
            SELECT oi
            FROM OrderItem oi
            WHERE oi.orders.code = :orderCode
        """
    )
    List<OrderItem> findAllByOrderCode(String orderCode);

JPA에서의 JPQL
EntityFactoryManager을 통해 EntityManager 객체를 생성 후 JPQL을 사용하여 데이터 조회하기

  • JPA 설정 XML파일 정의
    src/main/resources/META-INF/persistence.xml로 생성

    <class>를 통해 영속성 컨텍스트에 등록할 DB Entity 클래스를 정의
    ▶ 이후 Hibernate에 의해 생성된 ddlDB로 전송되어 자동으로 매핑DB Table을 생성
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="hibernate-exp-6">
        <class>model.s03.Member</class>
        <class>model.s03.Address</class>
        <class>model.s03.Product</class>        
        <class>model.s03.Category</class>
        <class>model.s03.OrderItem</class>
        <class>model.s03.Order</class>
        <properties>
<!-- DB 접속정보 정의 -->
            <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test-db;" />
            <property name="jakarta.persistence.jdbc.user" value="sa" />
            <property name="jakarta.persistence.jdbc.password" value="" />
            <property name="jakarta.persistence.schema-generation.database.action" value="create" />
<!-- SQL 로깅 -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.highlight_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="elipselink.logging.level" value="INFO"/>
            <property name="elipselink.logging.level.sql" value="FINE"/>
            <property name="elipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence> 
  • EntityManager 객체 생성 및 실습을 위한 초기화 코드 작성
    EntityManagerFactory 생성 시 <persistence-unit> 태그name 속성을 입력

    EntityManager 객체는 한 작업 당 한 객체 씩 생성 후 작업을 수행하며, 작업이 끝난 경우 자원 해제를 해야한다.
    ▶ 내부 SessionDB Connection을 포함하므로 사용 후 자원 해제를 통해 DB Connection Pool로 반환

    EntityTransaction 객체를 통해 JPA에 의한 DB 트랜잭션을 직접 제어
    Spring에서는 @Transactional에 의해 추상화
public class JpqlTests {
	private static EntityManagerFactory emf;
	Member m;
	@BeforeAll
	public static void setUpStatic() {
		emf = Persistence.createEntityManagerFactory("hibernate-exp-6");
	}
	@AfterAll
	public static void tearDownStatic() {
		emf.close();
	}
	@BeforeEach
	public void setUp(){
		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		try{
			tx.begin();
			m = new Member(
				"정수",
				"wjd747",
				"wjdtn%d@naver.com".formatted(747),
				new Address(
					"2",
					"3",
					"4"
				)
			);
			em.persist(m);
			tx.commit();
		} catch(Exception e){
			tx.rollback();
			throw new RuntimeException("Error Occur",e);
		} finally {
			em.close();
		}
	}
 }

▶ 실습을 위한 Member 객체 생성 및 EntityManager영속성 컨텍스트에 반영 후 EntityManager 객체자원 해제

  • JPQL문을 통한 SELECT문 으로 데이터 조회
    Query객체.setParameter("변수명","값") : JPQL문매개변수수를 바인딩:변수명으로 지정

    다건조회Query객체.getResultList()를 통해 다건조회Entity클래스 객체List<클래스> 객체로 반환
@Test
	void 멤버객체찾기_성공() {
		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		try{
			tx.begin();
			String JPQLTEXT = """
				SELECT m
				FROM Member m
				WHERE m.email = :email
				""";
			TypedQuery<Member> query = em.createQuery(JPQLTEXT, Member.class);
			query.setParameter("email", "'%s'".formatted(m.getEmail()));
			Member foundedMember = query.getSingleResult();
			Assertions.assertEquals(m.getId(), foundedMember.getId());
			tx.commit();
		} catch (Exception e) {
			tx.rollback();
			throw new RuntimeException(e);
		} finally {
			em.close();
		}
	}
  • 페이지네이션 구현하기
    페이지네이션

    Query 객체에서 offsetlimit을 지정하여 페이징처리된 결과 도출
    ▶ 결과 도출 시 우선 order by를 통해 정렬을 수행해야한다.

    query.setFirstResult(pageNum * pageSize).setMaxResults(pageSize);
    setFirstResult : offset 지정 : limit * 페이지번호
    setMaxResults : limit 지정
		@Test
		void 페이징_연습(){
			int pageSize = 10;
			int pageNum = 5;
			EntityManager em = emf.createEntityManager();
			EntityTransaction tx = em.getTransaction();
			String jpqlText = """
				SELECT m
				FROM Member m
				ORDER BY m.id desc
				""";
			try{
				tx.begin();
				TypedQuery<Member> query = em.createQuery(jpqlText, Member.class);
				TypedQuery<Member> pagedQuery = query.setFirstResult(pageNum * pageSize)
					.setMaxResults(pageSize);
				List<Member> members = pagedQuery.getResultList();
				members.stream().map(s -> s.getName()).forEach(System.out::println);
				tx.commit();
			} catch (Exception e){
				tx.rollback();
				throw new RuntimeException(e);
			} finally {
				em.close();
			}
		}

Spring JPA에서의 JPQL
JpaRepository상속하는 인터페이스@Query 어노테이션을 선언 후 내부에 JPQL문을 선언

// JPQL 방식 : Entity의 alias를 설정
	@Query("""
		SELECT EXISTS ( SELECT m FROM MemberEntity m WHERE m.loginId = ?1 )
	""")
	Boolean existsByLoginIdByJPQL(String loginId);
	@Query("""
		SELECT EXISTS ( SELECT m FROM MemberEntity m WHERE m.loginId = :loginId )
	""")
	Boolean existsByLoginIdByJPQL(String loginId);
profile
공부기록 블로그

0개의 댓글