JPA/JPQL
[JPQL] 다형성 쿼리, 엔티티 직접 사용, Named 쿼리, 벌크 연산
yoon_seon
2023. 4. 26. 16:45
📌 다형성 쿼리
Album, Movie, Book이 Item을 상속받는 구조 설계.
Type
- 조회 대상을 특정 자식으로 한정
- ex. Item 중에 Book, Movie를 조회해라
[JPQL]
select i from Item i where type(i) IN (Book, Movie)
[SQL]
select i from i where i.DTYPE IN ('B', 'M')
TREAT(JPA 2.1)
- 자바 타입 캐스팅과 유사
- 상속구조에서 부모타입을 특정 자식타입으로 다룰 때 사용
- FROM, WHERE, SELECT(Hibernate 지원) 사용
- ex. 부모인 Item과 자식 Book이 있다.
[JPQL]
select i from Item i where treat(i as Book).auther = 'kim'
[SQL]
select i from i where i.DTYPE IN ('B') and i.auther = 'kim'
📌 엔티티 직접 사용
엔티티 직접사용 - 기본 키 값
- JPA에서 엔티티를 직접 사용하면 SQL에서 해당 엔티티의 기본 키 값을 사용
[JPQL]
select count(m.id) from Member m // 엔티티의 아이디를 사용
select count(m) from Member m // 엔티티를 직접사용 → 기본 키 값을 사용한다.
[SQL]
select count(m.id) as cnt from Member m - 엔티티를 파라미터나 식별자로 직접 전달
// 엔티티를 파라미터로 전달
String query = "select m from Member m where m = :member";
List resultList = em.createQuery(query)
.setParameter("member", member)
.getResultList();
// 식별자를 직접 전달
String query = "select m from Member m where m.id = :memberId";
List resultList = em.createQuery(query)
.setParameter("memberId", memberId)
.getResultList();
실행 된 SQL
select m.* from Member m where m.id = ?
엔티티 직접사용 - 외래키 값
- JPA에서 엔티티를 직접 사용하면 SQL에서 해당 엔티티의 기본 키 값을 사용
Team teamA = em.find(Team.class, 1L);
String query = "select m from Member m where m.team = :team";
List resultList = em.createQuery(query)
.setParameter("team", teamA)
.getResultList();
String query = "select m from Member m where m.team.id = :teamId";
List resultList = em.createQuery(query)
.setParameter("teamId", teamId) // Team 엔티티에 설정되있는 외래키명
.getResultList()
실행된 SQL
select m.* from Member m where m.team_id = ?
📌 Named 쿼리
- 미리 정의해서 이름을 부여해 두고 사용하는 JPQL
- 정적쿼리만 가능
- 어노테이션, XML에 정의한다.
어노테이션 정의
// ...
@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();
Xml에 정의
//[META_INF?persistence.xml]
<persistence-unit name="jpabook">
<mapping-file>META-INF/ormMember.xml</mapping-file>
//[META-INF/ormMember.xml]
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="htt://xmlns.jcp.org/xml/ns/persistence/orm" version="2.1">
<named-query name="Member.findByUsername">
<query>
<![CDATA[ select m from Member m where m.username = :username]]
</query>
</named-query>
</entity-mappings>
- 사용법은 @NamedQuery의 query를 사용방법과 같다.
- Xml이 항상 우선권을 가진다.
- 애플리케이션 운영 환경에 따라 다른 Xml을 배포할 수 있다.
- 애플리케이션 로딩 시점에 초기화 후 재사용
- 애플리케이션 로딩 시점에 @NamedQuery 지정해둔 쿼리 파싱하여 검증
참고 : SpringData JPA를 사용한다면 이미 NamedQuery를 사용하고 있는 것이다.
@Repository
public interface MemberRepository extends JpaRepository<Member, Long>{
@Query("select u from User u where u.username = ?1")
Member findByUsername(String username);
}
@Repository annotation이 등록된 인터페이스에서 사용되는 @Query annotation에 있는 JPQL(or native)들이 NamedQuery로써 컴파일시에 등록되는 것이다.
📌 벌크 연산
- 벌크연산은 우리가 알고있는 SQL의 UPDATE, DELETE 문이라고 생각하면 된다.
ex. 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면? - 만약 JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL이 실행되어야 한다.
- 재고가 10개 미만인 상품을 리스트로 조회한다.
- 상품 엔티티의 가격을 10% 증가한다.
- 트랜잭션 커밋 시점에 변경감지가 동작한다.
- 변경된 데이터가 100건이라면 UPDATE SQL 100번 실행되야 한다.
벌크 연산 예제
- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
- executeUpdate()의 결과는 영향받은 엔티티 수 반환
- UPDATE, DELETE 지원
- INSERT(insert into ... select, 하이버네이트 지원)
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate();
System.out.println("result : "+resultCount); // 영향을 받은 쿼리 count
벌크 연산 주의
- 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리 한다.
- 벌크 연산을 실행하면 flush 된다.
- 벌크 연산을 먼저 실행한다.
- 벌크 연산 수행 후 영속성 컨텍스트 초기화한다.( em.clear() )
: 이미 영속성 컨텍스트에 올라가 있는 엔티티 존재하는데 벌크 연산이 실행되면서 flush가 되어 버리면 DB와 객체가 싱크가 맞지 않기 때문에 벌크 연산을 수행 후 영속성 컨텍스트를 초기화하여 싱크를 맞춘다.
참고 : SpringData JPA를 사용한다면 @Modifying을 통해 벌크연산이 가능하다.
해당 글은 인프런의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 강의를 정리한 내용입니다.
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com