
JPQL이란?
Java Persistence 쿼리 언어(JPQL)는 엔터티를 저장하는 데 사용되는 메커니즘과 관계없이 영구 엔터티에 대한 검색을 정의하는 데 사용된다. 따라서 JPQL은 "이식성"이 뛰어나 특정 데이터 저장소에 국한되지 않는다. Java Persistence 쿼리 언어는 Enterprise JavaBeans 쿼리 언어의 확장으로 EJB QL, 대량 삭제 및 업데이트, 조인 작업, 집계, 프로젝션, 하위 쿼리 등의 작업을 지원한다. 또한, JPQL 쿼리는 메타데이터에 정적으로 선언하거나 코드에 동적으로 내장할 수 있다.
JPQL과 SQL의 차이점
JQPL
엔티티 객체를 대상으로 쿼리문을 작성한다. SQL과 비슷하지만 쿼리문을 엔티티를 기준으로 작성하고, JPA가 SQL로 변환하여 실행한다. 엔티티 객체나 값 타입을 반환하며, JPA 환경에 의존한다.
SQL
데이터베이스 테이블을 대상으로 쿼리문을 작성한다. 테이블과 컬럼 기준으로 작성하며, 직접 데이터베이스에 바로 실행한다. 테이블의 행(ROW) 데이터를 반환하며, 데이터베이스에 직접 의존한다.
JPQL 기본문법
SELECT
SELECT e FROM Member e WHERE e.age > 20
FROM 절
FROM 엔티티이름 [AS] 별칭
- AS는 생략가능
WHERE 절
WHERE 조건식
ORDER BY 절
ORDER BY e.name DESC
GROUP BY / HAVING 절
SELECT t.teamName, COUNT(m) FROM Team t
JOIN t.members m
GROUP BY t.teamName
HAVING COUNT(m) > 5
JOIN 문
SELECT m FROM Member m JOIN m.team t WHERE t.name = 'A팀'
- 엔티티의 연관관계 필드로 조인
JPQL의 문법은 SQL에서 기초하기 때문에 비슷한 부분이 많지만, 대상이 테이블이 아니라 객체인 것이 가장 큰 차이점이다.
Entity와 테이블의 차이
Entity
자바 프로그램 안에서 다루는 객체이다. 애플리케이션(JAVA 코드)에 존재하며, 필드(속성)와 메서드로 구성되어 있다. 객체 참조형으로 관계를 표현하며, JPA가 관리한다. 비즈니스 로직 중심으로 설계하기 위한 목적을 가지고 있다.
테이블
데이터베이스(DB)에 존재한다. 컬럼, 제약조건 등으로 구성되어 있으며, 외래 키로 관계를 표현한다. DBMS가 관리하며, 데이터 저장과 조회 중심 설계를 위한 목적을 가지고 있다.
파라미터 바인딩
파라미터 바인딩이란?
파라미터 바인딩은 JPQL 쿼리에서 직접 값을 집어넣지 않고, 변수처럼 지정해두고 나중에 값을 연결(바인딩)하는 방법을 말한다. 이를 통해 쿼리 재사용을 높이고, SQL injection 같은 보안 문제를 막을 수 있으며, 코드의 가독성과 유지보수성도 훨씬 좋아진다.
파라미터 바인딩의 종류
1. 위치 기반 바인딩 (Positional Binding)
Query query = em.createQuery("SELECT m FROM Member m WHERE m.name = ?1");
query.setParameter(1, "지은");
?숫자 형식으로 파라미터를 지정하고, setParameter(순번, 값) 으로 값을 채워 넣는 방식이다.
2. 이름 기반 바인딩 (Named Binding)
Query query = em.createQuery("SELECT m FROM Member m WHERE m.name = :name");
query.setParameter("name", "지은");
:이름 형식으로 파라미터를 지정하고, setParameter("이름", 값) 으로 바인딩하는 형식이다. JPQL에서는 이름 기반 바인딩을 더 권장한다.
파라미터 바인딩 사용시 장점
1. 보안 강화 : SQL injection 공격을 방어할 수 있다.
2. 쿼리 재사용 : 같은 쿼리를 다양한 값으로 재사용할 수 있다.
3. 코드 관리 : 쿼리와 데이터가 분리되어 코드 가독성이 좋아진다.
JOIN 사용하기
내부 조인 (INNER JOIN)
SELECT m FROM Member m JOIN m.team t WHERE t.name = 'teamA'
연관된 엔티티끼리 매칭되는 데이터만 조회하며, INNER 키워드는 생략할 수 있다.
외부 조인 (LEFT OUTER JOIN)
SELECT m FROM Member m LEFT JOIN m.team t
연관 관계가 없어도 왼쪽 엔티티(Member)는 무조건 조회한다. LEFT를 꼭 명시해야 한다.
(JQPL에서 외부조인은 LEFT JOIN과 RIGHT JOIN 2가지가 존재하지만, RIGHT JOIN은 LEFT JOIN의 방향을 바꿔 반대로 결과를 가져와야 한다. RIGHT JOIN은 표기법에서 지원되지 않는다.)
페치 조인 (FETCH JOIN)
SELECT m FROM Member m JOIN FETCH m.team
연관된 엔티티를 즉시 함께 조회해서, N+1 문제를 예방하는 특별한 JOIN이다. SELECT 대상이 엔티티여야 한다.
CRUD 예제
CREATE
Member member = new Member();
member.setName("지은");
member.setAge(20);
em.persist(member);
JPQL에서는 INSERT를 사용하지 않는다. 대신 엔티티를 만들고, persist() 해야 한다.
READ
Member member = em.createQuery(
"SELECT m FROM Member m WHERE m.name = :name", Member.class)
.setParameter("name", "지은")
.getSingleResult();
getSingleResult()는 단건 조회일 경우 사용한다. 없거나 여러 개면 예외가 발생한다.
List<Member> members = em.createQuery(
"SELECT m FROM Member m WHERE m.age > :age", Member.class)
.setParameter("age", 18)
.getResultList();
getResultList()는 결과가 여러 건일 때 사용한다.
UPDATE
int updatedCount = em.createQuery(
"UPDATE Member m SET m.age = :age WHERE m.name = :name")
.setParameter("age", 25)
.setParameter("name", "지은")
.executeUpdate();
executeUpdate()를 호출하면 바로 DB에 반영된다. 이렇게 수정하면 영속성 컨텍스트를 무시하고 바로 DB에 적용된다.
DELETE
int deletedCount = em.createQuery(
"DELETE FROM Member m WHERE m.name = :name")
.setParameter("name", "지은")
.executeUpdate();
executeUpdate()로 삭제 쿼리를 실행한다.
Reference
10.2. JPQL Language Reference
The SELECT clause denotes the query result. More than one value may be returned from the SELECT clause of a query. The SELECT clause may contain one or more of the following elements: a single range variable or identification variable that ranges over an e
docs.oracle.com
'java' 카테고리의 다른 글
| [개념] JAVA의 어노테이션과 라이브러리 (2) | 2025.05.21 |
|---|---|
| [개념] JPA란 무엇인가 : JPA와 엔티티의 연관관계 (5) | 2025.04.08 |