728x90
반응형
다형성 쿼리
상속 관계에 있는 엔티티 조회 시 다형성을 사용하여 특정 엔티티 타입만 조회할 수 있다.
예제 구조
Type
- 조회 대상을 특정 자식으로 한정
TYPE(부모 엔티티 별칭)
- JPQL의
TYPE()
이 SQL에서는 DTYPE(= 구분컬럼)으로 변경되어 실행된다.
Book book = new Book();
book.setName("new bookname");
book.setAuthor("new author");
em.persist(book);
Movie movie = new Movie();
movie.setActor("new actor");
movie.setDirector("new director");
em.persist(movie);
// TYPE()
String query = "select i from Item i where type(i) in (Book, Movie)";
em.createQuery(query, Item.class).getResultList();
Treat
- 자바의 형변환과 유사하다.
- 상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용한다.
- FROM, WHERE, SELECT(하이버네이트 지원)절에서 사용한다.
TREAT(부모 엔티티AS 자식 엔티티).자식 엔티티가 갖고있는 필드
Book book = new Book();
book.setName("new bookname");
book.setAuthor("new author");
em.persist(book);
Movie movie = new Movie();
movie.setActor("new actor");
movie.setDirector("new director");
em.persist(movie);
// TREAT()
String query = "select i from Item i where treat(i as Book).author = 'new author'";
List<Item> result = em.createQuery(query, Item.class).getResultList();
for(Item i : result) {
System.out.println("item : " + i.getName());
}
엔티티 직접 사용
JPQL에서 엔티티를 직접 사용하게 되면 해당 엔티티의 기본키 값을 사용한다.
기본키 값
엔티티나 식별자를 파라미터로 전달해도 동일하게 기본값을 사용하여 동작한다.
엔티티 파라미터 바인딩
// 엔티티를 파라미터로 전달
String query = "select m from Member m where m = :member";
List<Member> result = em.createQuery(query, Member.class).setParameter("member", member1).getResultList();
for (Member member : result) {
System.out.println("member : " + member);
}
식별자 파라미터 바인딩
// 식별자를 파라미터로 전달
String query = "select m from Member m where m.id = :memberId";
List<Member> result = em.createQuery(query, Member.class).setParameter("memberId", member1.getId()).getResultList();
for (Member member : result) {
System.out.println("member : " + member);
}
동작 결과
외래키 값
외래키는 엔티티 내 @JoinColumn
으로 설정된 컬럼 값을 사용한다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID") // 외래키 지정, 비교 컬럼
private Team team;
@Enumerated(EnumType.STRING)
private MemberType type;
// getter, setter, toString
}
// 외래키 값
// 비교 컬럼은 @JoinColumn으로 지정된 컬럼
// 비교 값은 엔티티 기본키 값
String query = "select m from Member m where m.team = :team";
List<Member> result = em.createQuery(query, Member.class).setParameter("team", teamA).getResultList();
Named 쿼리
미리 정의해서 이름을 부여해두고 사용하는 JPQL
특징
- 정적 쿼리
- 어노테이션 또는 XML에 정의한다.
- XML 설정이 우선권을 가지며 애플리케이션 운영 환경에 따라 다른 XML을 배포할 수 있다.
- 애플리케이션 로딩 시점에 쿼리를 검증하고 초기화 후 재사용한다.
- 실무에서는 Spring Data JPA를 사용하여 DAO 단에서 @Query 어노테이션을 사용하여 Named쿼리처럼 사용하며 해당 방식이 더 효율적이다.
예제
어노테이션 방식
@Entity
@NamedQuery(
name = "Member.findByUsername"
, query = "select m from Member m where m.username = :username"
)
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@Enumerated(EnumType.STRING)
private MemberType type;
// getter, setter, toString
}
XML 방식
<!-- META-INF/ormMember.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://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>
<named-query name="Member.count">
<query>select count(m) from Member m</query>
</named-query>
</entity-mappings>
<!-- META-INF/persistence.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="hello">
<mapping-file>META-INF/ormMember.xml</mapping-file> <!-- Named쿼리 설정 -->
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test" />
<property name="hibernate.dialect" value="dialect.MyH2Dialect" />
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.jdbc.batch_size" value="10" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.default_batch_fetch_size" value="100" />
</properties>
</persistence-unit>
</persistence>
Main
// Named 쿼리
List<Member> result = em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", "member1")
.getResultList();
for (Member member : result) {
System.out.println("member : " + member);
}
동작 결과
벌크 연산
특정 PK로 지정된 데이터의 UPDATE, DELETE를 제외한 나머지 UPDATE, DELETE 동작 (쿼리 한번으로 여러 테이블 로우 변경)
특징
executeUpdate()
를 사용하여 영향받은 엔티티 수를 반환 받을 수 있다.- 기본적으로 UPDATE, DELETE를 지원하며 하이버네이트 구현체 사용 시 INSERT INTO SELECT를 사용할 수 있다.
예제
// 벌크 연산
// 전체 회원 나이 20살 변경
int updateCount = em.createQuery("update Member m set m.age = 20").executeUpdate();
System.out.println("update count : " + updateCount);
주의
- 벌크 연산은 영속성 컨텍스트를 무시하고 바로 데이터베이스에 직접 쿼리한다.
- 데이터베이스에 직접 쿼리하기 때문에 영속성 컨텍스트에 있는 엔티티 값 변경 후 조회를 해도 원하는 결과를 얻을 수 없다. 따라서 영속성 컨텍스트가 비어있는 상태로 벌크 연산을 먼저 실행하거나 벌크 연산 후 영속성 컨텍스트를 초기화 한 뒤 조회동작을 하게되면 원하는 결과를 얻을 수 있다.
영속성 컨텍스트 미초기화 예제
// 벌크 연산
// 영속성 컨텍스트 초기화 X
// 벌크연산으로 나이 20세로 변경했지만 조회 시 변경되어있지 않음.
// Query 실행 시 자동 flush
em.createQuery("update Member m set m.age = 20").executeUpdate();
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember.age : " + findMember.getAge());
영속성 컨텍스트 초기화 예제
// 벌크 연산
// 영속성 컨텍스트 초기화 후 조회
// 벌크연산으로 나이 20세로 변경 후 영속성 컨텍스트 초기화하고 조회
// Query 실행 시 자동 flush
em.createQuery("update Member m set m.age = 20").executeUpdate();
em.clear();
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember.age : " + findMember.getAge());
728x90
반응형
'Dev > JPA' 카테고리의 다른 글
[JPA] JPA 활용 I - 프로젝트 환경설정 (0) | 2021.09.14 |
---|---|
[JPA] JPA 활용 I - 강좌 소개 (0) | 2021.09.14 |
[JPA] 객체지향 쿼리 언어 - 중급문법 (1) (0) | 2021.09.10 |
[JPA] 객체지향 쿼리 언어 - 기본문법 (2) (0) | 2021.09.08 |
[JPA] 객체지향 쿼리 언어 - 기본 문법 (1) (0) | 2021.09.07 |
댓글