김영한의 ORM 표준 JPA 프로그래밍(기본편) - JPQL

2025. 2. 8. 12:55·김영한의 ORM 표준 JPA 프로그래밍(기본편)

Question

  • JPQL로 처리할 수 없는 복잡한 쿼리는 어떠한 방법으로 처리 가능한가?
  • getSingleResult 사용할 떄 주의할 점은?
  • 파라미터 바인딩의 2가지 방법에 대해 설명하고 무엇을 사용하는게 더 좋은지 설명하시오
  • JPA 프로젝션에서 여러 값 조회할 때 좋은 방법을 설명하시오
  • inner join과 left join의 차이는?
  • 세타 조인에 대해 설명하시오
  • Join시 조건을 on과 where절에 넣는 것의 차이는?
  • 경로 표현식에서 묵시적 조인 사용시 주의점은?
  • 페치 조인과 일반 조인의 차이는?
  • 페치 조인에서 일대다 관계 조회시 주의점과 해결 방안은?
  • 페치조인에서 별칭을 사용하지 않는 이유는?
  • 컬렌션을 페치조인하면 페이징 API를 사용할 수 없는 이유는?
  • 페치조인보다 일반 조인을 사용해야 할 케이스는?
  • Named 쿼리의 장점은?
  • 벌크 연산 사용시 주의점은?

 

 

JPA의 쿼리 방법

  • JPQL
    • JPA 쿼리의 기본 문법
    • QueryDSL을 사용하더라도 JPQL 기본 숙지가 되야함
  • JPA Criteria
    • 여러 기능을 제공하지만 가독성이 좋지 않고 복잡해 잘 사용하지 않음
  • QueryDSL
    • 쿼리를 Java코드와 같이 짤 수 있어 쿼리에 문제가 있을 시 컴파일 에러로 잡을 수 있음
    • 단순하고 쉬우며 동적쿼리 작성도 편함
    • 실용적으로 활용 가능해 실무에서 사용 가능  
  • 네이티브SQL
    • Sting으로 된 진짜 SQL 쿼리를 날려서 사용하는 방법
    • JPQL 해결이 안될 때 사용할 수 있지만 아래 다른 라이브러릴 활용이 일반적으로 더 나음
  • JDBC API 직접 사용, MyBatis, SpringJdbcTemplate
    • 네이티브 SQL 처럼 JPQL 처럼 해결이 되지 않는 경우 활용할 수 있는 방법
    • 주의 점: 영속성 컨텍스트가 반영되어 있지 않으면 결과가 달라질 수 있으므로 JPA와 함께 사용할 경우에는 SQL 실행 전 영속성 컨텍스트를 수동 플러시 해줘야함(JPQL은 날리면 그 전에 자동 플러시됨)

 

 

JPQL

  • JPA를 사용하면 DB를 엔티티 객체 중심으로 개발 가능
  • 모든 DB 데이터를 객체로 변환해서 검색은 불가능
  • 필요한 데이터만 뽑아 오려면 검색 조건이 포함된 SQL이 필요
  • JPA는 SQL을 추상화한 JPQL 이라는 객체 지향 쿼리 언어 제공
  • SQL과 유사하며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 기본 지원
  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리
  • 특정 DB  SQL에 의존하지 않는 객체 지향 SQL

 

JPQL 기본 문법

  • select m from Member as m where m.age > 18
  • 엔티티와 속성은 대소문자 구분 필요(Member, age)
  • JPQL 키워드는 대소문자 구분 필요 없음(SELECT, FROM, where)
  • 엔티티 이름을 사용하고, 테이블 이름을 사용하는게 아님
  • 별칭은 필수(m) (as는 생략 가능)

 

집합과 정렬

  • 기본적인 COUNT, SUM, AVG, MAX, MIN 제공
  • GROUP BY, HAVING, ORDER BY 또한 제공

 

TypeQuery, Query

TypedQuery<Member> query = entityManager.createQuery(SELECT m FROM Member m, Member.class);
List<Object[]> results = query.getResultList();

Query query = entityManager.createQuery(SELECT m.name, m.age FROM Member m);
Double averageAge = query.getSingleResult();
  • TypeQuery: 반환 타입이 명확할 때 사용
  • Query: 반환 타입이 명확하지 않을 때 사용

 

결과 조회: getResultList, getSingleResult

TypedQuery<Member> query = entityManager.createQuery(SELECT m FROM Member m, Member.class);
List<Object[]> results = query.getResultList();

Query query = entityManager.createQuery(SELECT m.name, m.age FROM Member m);
Double averageAge = query.getSingleResult();
  • query.getResultList(): 결과가 하나 이상일 때, 리스트 반환
    • 결과과 없으면 빈 리스트 반환(널 포인터 에러 나지 않음)
  • query.getSingleResult(): 결과가 정확히 하나, 단일 객체 반환
    • 하나가 아니면 에러가 나는 상황이 발생할 수 있음 
    • 결과가 없으면: javax.persistence.NoResultException
    • 둘 이상이면: javax.persistence.NonUniqueResultException
    • 스프링 데이터 JPA 에서는 이를 감싸서 에러가 나지 않도록 함

 

파라미터 바인딩: 이름 기준, 위치 기준

//이름 기준
SELECT m FROM Member m where m.username=:username
query.setParameter("username", usernameParam);

//위치 기준
SELECT m FROM Member m where m.username=?1
query.setParameter(1, usernameParam);
  • 이름 기준
    • 이름에 맞는 파라미터 넣어 주는 방식
    • 일반적으로 이 방식을 사용
  • 위치 기준
    • 위치 번호에 따라 파라미터 맵핑
    • 중간에 새로운 파라미터 넣으면 숫자를 뒤로 다 미뤄야 해서 잘 사용하지 않음

 

프로젝션

  • SELECT 절에 조회할 대상을 지정하는 것
  • 프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문다 등 기본 데이터 타입)
    • SELECT m FROM Member m -> 엔티티 프로젝션
    • SELECT m.team FROM Member m -> 엔티티 프로젝션
    • SELECT m.address FROM Member m -> 임베디드 타입 프로젝션
    • SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션
//Query 타입으로 조회
Query query = entityManager.createQuery("SELECT m.name, m.age FROM Member m");
List<Object[]> results = query.getResultList();
        
//Object[]로 조회        
TypedQuery<Object[]> query = entityManager.createQuery("SELECT m.name, m.age FROM Member m", Object[].class);
List<Object[]> results = query.getResultList();

//new 명령어로 조회
TypedQuery<MemberDTO> query = entityManager.createQuery(
	"SELECT new MemberDTO(m.name, m.age) FROM Member m", MemberDTO.class);
List<MemberDTO> results = query.getResultList();
  • 여러 값 조회
    • Query 타입으로 조회
    • Object[]로 조회
    • new DTO로 조회
      • 장점
        • 타입 안정성과 가독성이 뛰어남
        • 반환된 DTO는 바로 사용 가능하므로 추가 형변환이 필요 없음
        • 코드 유지보수가 좋음
      • 단점
        • JPQL 쿼리 작성할 때 DTO의 생성자를 정확히 맞춰 작성해야 함

 

 

페이징

String jpql = "select m from Member m order by m.name desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
	.setFirstResult(10)
	.setMaxResults(20)
	.getResultList();
  • DB마다 페이징 쿼리가 매우 다르고 특정 DB에서는 매우 복잡할 수 있는데 JPA는 손쉽게 사용 가능
  • setFirstResult(int startPosition): 조회 시작 위치(0 부터)
  • setMaxResults(int maxResult): 조회할 데이터 수

 

JOIN

//내부 조인
SELECT m.name, o.amount FROM Members m INNER JOIN Orders o

//외부 조인
SELECT m.name, o.amount FROM Members m LEFT OUTER JOIN Orders o

//세타 조인
SELECT m.name, o.amount FROM Members m, Orders o WHERE m.member_id = o.member_id;

//ON과 WHERE 차이
SELECT m.name, o.amount FROM Members m INNER JOIN Orders o ON m.member_id = o.member_id;
SELECT m.name, o.amount FROM Members m INNER JOIN Orders o WHERE m.member_id = o.member_id;
  • 내부 조인( SELECT m FROM Member m [INNER] JOIN m.team t)
    • 그냥 JOIN만 쓰면 inner 조인
    • JOIN 오른쪽 테이블에 매칭되는 데이터가 없으면 데이터가 안나옴
  • 외부 조인( SELECT m FROM Member m LEFT [OUTER] JOIN m.team t)
    • LEFT JOIN 이라고 사용하면 LEFT OUTER JOIN
      • JOIN 오른쪽 테이블에 매칭되는 데이터가 없어도 null로 채워서 다 나옴
    • RIGHT JOIN 이라고 사용하면 RIGHT OUTER JOIN
      • JOIN 왼쪽 테이블에 매칭되는 데이터가 없어도 null로 채워서 다 나옴
  • 세타 조인( select count(m) from Member m, Team t where m.username = t.name)
    • JOIN을 사용하지 않고 , 로만 사용
    • 왼쪽 테이블 X 오른쪽 테이블로 다 일단 다 불러온 후 where절로 처리
    • 쿼리 복잡도와 성능 이슈로 일반적으로 잘 사용하지 않고 테스트용으로 사용
  • ON 절 사용(JPA 2.1부터 지원)
    1. 연관관계가 맵핑되어 있으면 PK로 자동 ON을 수행함
    2. WHERE 절은 JOIN 이후에 필터링을 하는 것이고, JOIN 절은 JOIN 중에 필터링 하는 것
    3. 따라서, 결과가 달라지며 상황에 맞게 사용해야 함

예시

SELECT m, t FROM Member m LEFT JOIN m.team t ON t.name = 'A'
SELECT m, t FROM Member m LEFT JOIN m.team t WHERE t.name = 'A'

 

 

서브 쿼리

//팀A 소속인 회원
select m from Member m
where exists (select t from m.team t where t.name = ‘팀A')

//전체 상품 각각의 재고보다 주문량이 많은 주문들
select o from Order o
where o.orderAmount > ALL (select p.stockAmount from Product p)

//어떤 팀이든 팀에 소속된 회원
select m from Member m
where m.team = ANY (select t from Team t)
  • 서브쿼리 지원 함수
    • [NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참
    • {ALL | ANY | SOME} (subquery)
    • ALL 모두 만족하면 참
    • ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
    • [NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
  • JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능한데, 하이버네이트에서는 SELECT 절 지원
  • 서브 쿼리를 원래 FROM절에는 지원이 안되었는데 하이버네이트 6부터 지원
    • 원래 조인으로 풀 수 있으면 조인으로 풀어서 해결함

 

 

JPQL 표현 타입

// JPQL 예시 코드
String jpql = "SELECT m FROM Member m WHERE " +
              "m.name = 'HELLO' AND " +
              "m.description = 'She''s' AND " +
              "m.age = 10L AND " +
              "m.salary = 10D AND " +
              "m.height = 10F AND " +
              "m.isActive = TRUE AND " +
              "m.type = jpabook.MemberType.Admin AND " +
              "TYPE(m) = Member";

// 엔티티 매니저를 사용해서 쿼리 실행
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
  •  문자: 'Hello', 'She''s'
  • 숫자: 10L(Long), 10D(Double), 10F(Float)
  • Bolean: TRUE, FALSE
  • ENUM: jpabook.MemberType.Admin(패키지명도 들어가야 함)
  • 엔티티 타입: TPYE(m) = Member(상속 관계에서 사용)

 

 

JPQL 기타 문법

String jpql = "SELECT m FROM Member m " +
              "WHERE EXISTS (SELECT t FROM Team t WHERE t = m.team) AND " +
              "m.age IN (20, 30, 40) AND " +
              "m.salary > 50000 AND " +
              "m.experience >= 5 AND " +
              "m.rank < 10 AND " +
              "m.joinDate <= :joinDate AND " +
              "m.status <> 'inactive' AND " +
              "m.score BETWEEN 50 AND 100 AND " +
              "m.notes LIKE '%experienced%' AND " +
              "m.manager IS NOT NULL AND " +
              "NOT (m.retired = TRUE)";
  • SQL과 문법이 같은 식
  • EXISTS, IN
  • AND, OR, NOT
  • =, >, >=, <, <=, <>
  • BETWEEN, LIKE, IS NULL

 

 

조건식 - CASE, COALESCE, NULLIF

//기본 CASE 식
select
     case when m.age <= 10 then '학생요금'
          when m.age >= 60 then '경로요금'
		  else '일반요금'
	end
from Member m

//단순 CASE 식
select
	case t.name
		when '팀A' then '인센티브110%'
		when '팀B' then '인센티브120%'
		else '인센티브105%'
	end
from Team t

//COALESCE(사용자 이름이 없으면 이름 없는 회원을 반환)
select coalesce(m.username,'이름 없는 회원') from Member m

//NULLIF(사용자 이름이 '관리자'면 null 반환, 나머지는 본인 이름 반환
select NULLIF(m.username, '관리자') from Member m
  • CASE 식은 기본 CASE 식, 단순 CASE 식 두 가지로 사용 가능
  • COALESCE: 하나씩 조회해서 null이 아니면 반환
  • NULLIF: 두 값이 같으면 null 반환, 다르면 첫 번째 값 반환

 

 

JPQL 기본 함수

String jpql = "SELECT CONCAT(m.firstName, ' ', m.lastName), " + // CONCAT
              "SUBSTRING(m.phoneNumber, 1, 3), " + // SUBSTRING
              "TRIM(m.address), " + // TRIM
              "LOWER(m.email), " + // LOWER
              "UPPER(m.department), " + // UPPER
              "LENGTH(m.notes), " + // LENGTH
              "LOCATE('Smith', m.fullName), " + // LOCATE
              "ABS(m.salary), " + // ABS
              "SQRT(m.bonus), " + // SQRT
              "MOD(m.experience, 2), " + // MOD
              "SIZE(m.projects), " + // SIZE
              "INDEX(t.members) " + // INDEX
              "FROM Member m " +
              "JOIN m.team t";
  • 문자열 함수
    • CONCAT: 두 개 이상의 문자열을 하나로 연결합니다.
    • SUBSTRING: 문자열의 일부분을 추출합니다.
    • TRIM: 문자열 양쪽의 공백을 제거합니다.
    • LOWER: 문자열을 소문자로 변환합니다.
    • UPPER: 문자열을 대문자로 변환합니다.
  • 문자열 길이 함수
    • LENGTH: 문자열의 길이를 반환합니다.
    • LOCATE: 특정 문자열이 다른 문자열 내에서 시작하는 위치를 반환합니다.
  • 수학 함수
    • ABS: 숫자의 절대값을 반환합니다.
    • SQRT: 숫자의 제곱근을 반환합니다.
    • MOD: 두 숫자를 나눈 나머지를 반환합니다.
  • 컬렉션 함수 (JPA 용도)
    • SIZE: 컬렉션의 크기를 반환합니다.
    • INDEX: JPA에서 List 컬렉션의 인덱스를 반환합니다.
  • 사용자 정의 함수
    • 하이버네이트트 사용 전 방언에 추가해서 사용 가능
    • 사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록
    • select function('group_concat', i.name) from Item i

 

 

경로 표현식

  • 점을 찍어 그래프를 탐색하는 것을 의미
  • 상태 필드 
    • 단순 값 저장을 위한 필드 (m.username)
    • 경로 탐색이 한 번 하면 무조건 끝
  • 연관 필드
    • 단일 값 연관 필드
      • @ManyToOne, @OneToOne, 대상이 엔티티인 경우(m.team)
      • 묵시적으로 내부 조인 발생하며 탐색 O
    • 컬렉션 값 연관 필드
      • @OneToMany, @ManyToMany, 대상이 컬렉션(m.orders)
      • 묵시적 내부 조인 발생하며 탐색X
      • FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능

 

명시적 조인, 묵시적 조인

  • 명시적 조인: join 키워드를 직접 사용
    • select m from Member m join m.team t
  • 묵시적 조인: 경로 표현식에 의해 묵시적으로 SQL 조인 발생
    • select m.team from Member m
    • 위오 같은 쿼리를 하면 team이 연관 필드이기 때문에 묵시적 내부 조인이 자동으로 발생
  • 예제
    • select o.member.team from Order o -> 성공
      • 멤버는 엔티티이므로 내부로 계속 탐색 가능
      • 하지만 조인에 조인이 일어나는 문제
    • select t.members.username from Team t -> 실패
      • members는 컬렉션이므로 컬렉션 내부로는 탐색 불가능
    • select m.username from Team t join t.members m -> 성공
      • 컬렉션을 별도의 조인을 명시적으로 하면 내부로 접근 가능
  • 묵시적 주의 사항
    • 항상 내부 조인으로 실행됨
    • 컬렉션은 명시적 조인을 통해 별칭을 얻어서 접근해야함
    • 컬렉션이 아니라 엔티티라도 묵시적 조인은 예기치 못한 조인이 계속 일어나므로 명시적 조인을 사용해야 함
    • 묵시적 조인은 SQL의 FROM (JOIN) 절에 영향을 주므로 명시적으로 해줘야 유지보수가 좋음
    • 추후 성능 향상에 영향을 주는게 JOIN인데 묵시적 조인이면 이를 개선하기가 어려움

 

페치 조인

//JPQL
select m from Member m join fetch m.team

//SQL
SELECT M.*, T.* FROM MEMBER M
INNER JOIN TEAM T ON M.TEAM_ID=T.ID
  • SQL의 기본 조인 종류는 아님
  • JPQ에서 성능 최적화를 위해 제공하는 기능
  • 연관 맵핑된 엔티티나 컬렉션을 SQL 조회 시 한꺼번에 조회할 때 사용
  • 위 예시처럼, JPQL에서 join fetch를 하면 아래 SQL처럼 전부 조회해서 나오게 됨
  • 또한, 이 때 team의 정보를 즉시 로딩으로 바로 불러옴

 

페치 조인과 일대다 관계

//JPQL
select t
from Team t join fetch t.members
where t.name = ‘팀A'

//SQL
SELECT T.*, M.*
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'

  • 일대다 관계에서 페치 조인시 join fetch 좌측에 있는 테이블은 결과값에 여러개가 들어갈 수 있음.
  • 따라서, 결과를 출력하면 원치 않게 여러번 출력이 되는 문제가 발생할 수 있음.
  • DISTINCT
    • 이는 기존 SQL의 DISTINCT로도 해결이 되지 않는데 그 이유는 오른쪽 테이블의 PK는 다르기 때문
    • JPA의 DISTINCT는 기존 SQL DISTINCT의 기능 + 애플리케이션에서 엔티티 중복 제거를 진행함
    • 즉, 위 예제에서 팀A가 2개가 때문에 하나를 제거해줌.

 

페치 조인과 일반 조인의 차이

//JPQL
select t
from Team t join t.members m
where t.name = ‘팀A'

//SQL
SELECT T.*
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'
  • 일반 조인시 member의 내용도 모두 select는 하지만, 실제 해당 테이블을 조회한 것은 아니고 가짜로 생성만 해 놓음.
  • 추후 필요한 시점에 불러서 사용하는 지연 로딩을 사용함
  • 페치 조인의 즉시 조인과 다른 점

 

 

페치 조인의 특징과 한계

  • JPA에서 페치 조인 대상에는 별칭을 줄 수 없음
    • 하이버네이트는 가능하지만 가급적 사용X
    • 페치 조인은 연관된 테이블을 한 번에 로드해 그래프를 완성하는 것에 있는 것이지
    • 페치 조인된 엔티티를 쿼리하는 것은 의미가 없음
  • 둘 이상의 컬렉션은 페치 조인 할 수 없음
    • 카르테시안 곱 문제 등으로 성능 문제 데이터 일관성 문제 등으로 허용하지 않음
  • 컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없음
    • 일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인을 해도 페이징이 가능
    • 하지만, 일대다, 다대다와 같은 상황에서는 이전에 페치 조인과 일대다관계에서 설명했듯이 대상 테이블의 값이 여러개가 나오게 되므로 의도한 대로 페이징을 할 수 없음
    • 문제는 하이버네이트는 이를 결고 로그만 남기고 메로리에서 페이징 하므로 매우 위험
  • 페치 조인은 성능 최적화를 위해 실무에서 매우 자주 사용되는 기술
  • 하지만, 모든 것을 페치 조인으로 해결할 수 는 없음
  • 페치 조인은 객체 그래프를 유지할 때 사용하면 좋음
  • 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면 페치 조인보다는 일반 조인을 사용하고, 필요한 데이터만 조회해서 DTO로 반환하는 것이 효과적

 

 

Type

//JPQL
select i from Item i
where type(i) IN (Book, Movie)

//SQL
select i from i
where i.DTYPE in (‘B’, ‘M’)
  • 조회 대상을 특정 자식으로 한정
  • Item 중에 Book, Movie를 조회하라
  • type(i) 이런식으로 사용하면 Discriminator로 변환됨

 

 

Treat

//JPQL
select i from Item i
where treat(i as Book).author = ‘kim’

//SQL
select i.* from Item i
where i.DTYPE = ‘B’ and i.author = ‘kim’
  • 자바의 타입 캐스팅과 유사
  • 상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용
  • FROM, WHERE, SELECT(하이버네이트 지원) 사용
  • 위 예제는 단일 엔티티 일때의 예제

 

엔티티 직접 사용 - 기본 키 값

//JPQL
select count(m.id) from Member m //엔티티의 아이디를 사용
select count(m) from Member m //엔티티를 직접 사용

//SQL(JPQL 둘다 같은 다음 SQL 실행)
select count(m.id) as cnt from Member m

String jpql = “select m from Member m where m = :member”;
List resultList = em.createQuery(jpql)
	.setParameter("member", member)
	.getResultList();
    
String jpql = “select m from Member m where m.id = :memberId”;
List resultList = em.createQuery(jpql)
	.setParameter("memberId", memberId)
	.getResultList();
  • JPQL에서 엔티티를 직접 사용하면 SQL에서 해당 엔티티의 기본 키 값을 사용

 

 

엔티티 직접 사용 - 외래 키 값

Team team = em.find(Team.class, 1L);
String qlString = “select m from Member m where m.team = :team”;
List resultList = em.createQuery(qlString)
	.setParameter("team", team)
	.getResultList(); 

String qlString = “select m from Member m where m.team.id = :teamId”;
List resultList = em.createQuery(qlString)
	.setParameter("teamId", teamId)
	.getResultList();
  • 외래키 값으로 엔티티를 직접 넣어도 외래 키 값으로 자동 맵핑이 되어짐

 

 

Named 쿼리 - 정적 쿼리

@Entity
@NamedQuery(
	name = "Member.findByUsername",
	query="select m from Member m where m.username = :username")
public class Member {
	...
}

List<Member> resultList =
	em.createNamedQuery("Member.findByUsername", Member.class)
	.setParameter("username", "회원1")
	.getResultList();
  • 미리 정의해서 이름을 부여해두고 사용하는 JPQL
  • 동적은 안되고 정적 쿼리만 가능
  • 어노테이션 또는 XML에 정의해서 사용
  • 애플리케이션 로딩 시점에 초기화 후 재사용 가능
  • 에플리케이션 로딩 시점이 쿼리를 검증하므로 컴파일 오류로 쿼리 문제 검출 가능

 

 

벌크 연산

// 특정 부서의 모든 직원의 급여를 10% 인상
String jpql = "UPDATE Employee e SET e.salary = e.salary * 1.1 WHERE e.department.name = :deptName";
int updatedCount = em.createQuery(jpql)
	.setParameter("deptName", "Engineering")
	.executeUpdate();
  • 쿼리 한 번으로 여러 테이블 로우 변경
  • executeUpdate()의 결과는 영향받은 엔티티 수 반환
  • UPDATE, DELETE, INSERT(하이버네이트) 지원
  • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
    • 따라서, 영속성 컨텍스트 작업 전 벌크 연산을 먼저 실행
    • 혹은 벌크 연산 수행 후 영속성 컨텍스트 초기화 실행

 

 

'김영한의 ORM 표준 JPA 프로그래밍(기본편)' 카테고리의 다른 글

김영한의 ORM 표준 JPA 프로그래밍(기본편) - 값타입, 임베디드 타입, 값 타입 컬렉션  (3) 2025.02.08
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 프록시, 지연로딩, Cascade, 고아 객체  (1) 2025.02.07
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 상속관계 맵핑과 - @MappedSuperclass  (1) 2025.02.06
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 다대일, 일대다, 일대일, 다대다  (1) 2025.02.05
김영한의 ORM 표준 JPA 프로그래밍(기본편) - 연관관계 단방향 맵핑, 양방향 맵핑  (1) 2025.02.05
'김영한의 ORM 표준 JPA 프로그래밍(기본편)' 카테고리의 다른 글
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 값타입, 임베디드 타입, 값 타입 컬렉션
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 프록시, 지연로딩, Cascade, 고아 객체
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 상속관계 맵핑과 - @MappedSuperclass
  • 김영한의 ORM 표준 JPA 프로그래밍(기본편) - 다대일, 일대다, 일대일, 다대다
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (118)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      reentarantlock
      requset scope
      jpq
      @args
      빈 후처리기
      프록시
      페치 조인
      @discriminatorvalue
      hibernate5module
      log trace
      버퍼
      cglib
      Thread
      @discriminatorcolumn
      조회 성능 최적화
      스레드
      단방향 맵핑
      락
      gesingleresult
      jdk 동적 프록시
      @within
      고급
      양방향 맵핑
      김영한
      Target
      자바
      typequery
      JPQL
      WAS
      프록시 팩토리
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    김영한의 ORM 표준 JPA 프로그래밍(기본편) - JPQL
    상단으로

    티스토리툴바