Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
- 1 - 과정명 : JPA와 Hibernate
교육 일정표
교육은 매 회 3 시간씩 총 5회에 걸쳐 진행합니다.
1 일차 2 일차 3 일차 4 일차 5 일차
5월 26일(월) 5월 27일(화) 5월 28일(수) 5월 29일(목) 5월 30일(금)
ORM 이해하기
• 영속성
• 패러다임 불일치
• 계층형 아키텍처
• 객체/관계형 매핑
• Quick Start
- Hibernate
• Hibernate 개요
• Hibernate 기본
• OR Mapping I
- Hibernate
• Spring과 Hibernate통합
• OR Mapping II
• 트랜잭션 관리
• Hibernate와 EJB
- JPA
• 도메인 모델과 JPA
• JPA 이용 도메인 객체 구현
• 엔티티 관계
• 엔티티 매핑
• 엔티티 관계 매핑
- JPA
• 상속 매핑
• EntityManager
• 질의 API
• JPQL
5.1 상속 매핑
5.2 EntityManager
5.3 질의API와 JPQL
5일차 – JPA
단일 테이블 전략
조인 테이블 전략
클래스 별 테이블 전략
다형성 관계 매핑
- 3 - 과정명 : JPA와 Hibernate
단일 테이블 전략
상속계층의 모든 클래스를 한 테이블로 매핑함
식별자(discriminator) 컬럼으로 계층 상의 객체를 구분함
식별자 컬럼은 객체의 타입 값을 가짐
매핑 annotation
식별자 컬럼
@Entity
@Table(name="USERS")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="USER_TYPE",
discriminatorType=DiscriminatorType.STRING, length=1)
public abstract class User ...
@Entity
@DiscriminatorValue(value="S")
public class Seller extends User ...
@Entity
@DiscriminatorValue(value="B")
public class Bidder extends User
- 4 - 과정명 : JPA와 Hibernate
조인 테이블 전략
일대일 관계를 이용하여 상속을 표현
각 엔티티 별로 테이블을 나누며, 상속 관계는 일대일 관계로 표현
부모 클래스에 해당하는 테이블은 자식 클래스들의 공통인 컬럼을 가짐
매핑 annotation @Entity
@Table(name="USERS")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="USER_TYPE",
discriminatorType=STRING, length=1)
public abstract class User ...
@Entity @Table(name="SELLERS") @DiscriminatorValue(value="S") @PrimaryKeyJoinColumn(name="USER_ID") public class Seller extends User ... @Entity @Table(name="BIDDERS") @DiscriminatorValue(value="B") @PrimaryKeyJoinColumn(name="USER_ID") public class Seller extends User ...
- 5 - 과정명 : JPA와 Hibernate
클래스 별 테이블 전략
상속 계층 상의 모든 클래스가 각각 테이블로 매핑되며 테이블은 관계가 없음
OO / Relational 관점에서 모두 바람직하지 않음
엔티티 검색시 SQL UNION을 사용하거나 각 엔티티를 별도의 SQL로 검색해야 함
@Entity
@Table(name="USERS")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class User {
...
@Entity
@Table(name="SELLERS")
public class Seller extends User {
...
@Entity
@Table(name="BIDDERS")
public class Bidder extends User {
- 6 - 과정명 : JPA와 Hibernate
상속 매핑 전략 비교
상속 매핑 전략 선택은 많은 고민을 필요로 함
특성 단일 테이블 조인 테이블 클래스 별 테이블
테이블 지원 모든 클래스를 한 테이블에 •컬럼이 널 가능 •하위 클래스 추가시 테이블이 확장됨
부모 클래스, 자식 클래스가 별도의 테이블로 매핑되고 조인으로 서로 묶음 매핑된 테이블은 정규화 됨
각 클래스 별 한 테이블이며 조인 관계 없음
식별자 컬럼 사용 예 예 아니오
엔티티 계층 검색 SQL 생성 단순 SELECT 조인을 포함한 SELECT 각 클래스별 하나의 SELECT 또는 SELECT의 UNION 사용
삽입/갱신을 위한 SQL 하나의 INSERT/UPDATE 여러 INSERT/SELECT, 부모 클래스와 각 하위 클래스용
각 클래스별 하나의 INSERT/UPDATE
다형성 관계 좋음 좋음 나쁨
다형성 질의 좋음 좋음 나쁨
EJB3 JPA 지원 필수 필수 선택사항
5.1 상속 매핑
5.2 EntityManager
5.3 질의API와 JPQL
5일차 – JPA
EntityManager소개
EntityManager 인스턴스 생성
지속성 오퍼레이션 관리
엔티티라이프사이클 리스너
엔티티 운영 가이드
- 8 - 과정명 : JPA와 Hibernate
EntityManager소개 : EntityManager 인터페이스 (1/2)
EntityManager
객체지향과 관계형 간의 다리 역할
도메인 객체를 테이블로 변환
엔티티 저장요청 시: 엔티티 객체를 생성하여, 데이터베이스 저장한 다음 객체지향 세계로 리턴하여 줌
SQL과 같은 CRUD 오퍼레이션 제공
강력한 기능에 비해 상대적으로 작고 단순하며 직관적인 인터페이스를 가짐
- 9 - 과정명 : JPA와 Hibernate
EntityManager소개 : EntityManager 인터페이스 (2/2)
메소드 시그너처 설명
public void persist(Object entity); 엔티티를 DB로 저장
public <T> T merge(T entity); EntityManager의 지속성 컨텍스트로 엔티티를 병합
public void remove(Object entity); DB로 부터 엔티티 삭제
public <T> T find(Class<T> entityClass, Object primaryKey); 일차키로 엔티티 인스턴스를 찾음
public void flush(); EntityManager의 지속성 컨텍스트 안의 엔티티를 DB와 동기화 함
public void setFlushMode(FlushModeType flushMode); EntityManager의 지속성 컨텍스트의 flush 모드를 변경함 (AUTO 또는 COMMIT)
public FlushModeType getFlushMode(); 현재 플러시 모드 검색
public void refresh(Object entity); DB의 엔티티를 리셋함
public Query createQuery(String jpqlString); JPQL 문을 이요하여 동적 질의 생성
public Query createNamedQuery(String name); 질의 인스턴스 생성
public Query createNativeQuery(String sqlString); public Query createNativeQuery(String sqlString, Class result Class); public Query createNativeQuery(String sqlString, String resultSetMapping);
원시 SQL문을 이용하여 동적 질의 생성
public void close(); EntityManager를 종료함
public boolean isOpen(); EntityManager 실행상태 확인
public EntityTransaction getTransaction(); 트랜잭션 객체 검색
public void joinTransaction(); 기존 JTA 트랜잭션 조인을 요청함
- 10 - 과정명 : JPA와 Hibernate
EntityManager소개 : 엔티티 라이프사이클
엔티티는 아주 단순한 라이프사이클을 가짐
SessionBean이나 MDB는 애플리케이션 시작과 함께 컨테이너로 로드됨
반면, EntityManager는 JPA 엔티티로 인식하기 전에는 POJO를 알지 못함
SessionBean이나 MDB는 처음부터 끝까지 컨테이너가 인식함
반면, EntityManager는 가능한 짧은 시간동안 엔티티를 인식하고 다루어야 함
관리되는 엔티티(managed entity)
- 11 - 과정명 : JPA와 Hibernate
EntityManager소개 : 지속성 컨텍스트, 범위, EntityManager (1/2)
지속성 컨텍스트(persistence context)
주어진 지속성 범위 내에서 EntityManager에 의해 관리되는 엔티티 컨테이너의 집합
지속성 범위는 엔티티를 관리하고 있는 기간임, 다음 두 가지 유형이 있음
• 트랜잭션(transaction)
• 확장 (extended)
EntityManager의 내부 기능에 가장 중요한 역할을 수행함
EntityManager는 엔티티의 상태관리를 현재 가용한 지속성 컨텍스트로 위임함
트랜잭션-범위 EntittyManager
트랜잭션 기간 동안 엔티티는 attach 상태이고, 종료 후 자동으로 detach 상태가 됨
- 12 - 과정명 : JPA와 Hibernate
EntityManager소개 : 지속성 컨텍스트, 범위, EntityManager (2/2)
확장-범위 EntityManager
여러 트랜잭션을 걸쳐서 라이프사이클이 지속됨
유상태 세션 빈과 함께 사용하고 빈 인스턴스가 살아있는 동안 계속 됨
엔티티의 관리대상 여부는 트랜잭션과 관계없음
빈 자체가 제거되든지 EntityManager가 종료되어야 범위가 끝남
- 13 - 과정명 : JPA와 Hibernate
EntityManager소개 : ActionBazaar 에서 EntityManager 사용
@Stateless
public class ItemManagerBean implements ItemManager {
@PersistenceContext(unitName="actionBazaar")
private EntityManager entityManager;
public ItemManagerBean() {}
public Item addItem(String title, String description, byte[] picture, double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
item.setDescription(description);
item.setPicture(picture);
item.setInitialPrice(initialPrice);
Seller seller = entityManager.find(Seller.class, sellerId);
item.setSeller(seller);
entityManager.persist(item);
return item;
}
public Item updateItem(Item item) {
entityManager.merge(item);
return item;
}
public Item undoItemChanges(Item item) {
entityManager.refresh(entityManager.merge(item));
return item;
}
public void deleteItem(Item item) {
entityManager.remove(entityManager.merge(item));
}
}
- 14 - 과정명 : JPA와 Hibernate
EntityManger 인스턴스생성 : 컨테이너-관리 EntityManager
Container-managed EntityManager
@PersistenceContext annotation을 이용 주입됨
지속성 유닛은 소스코드로 설정할 수 없으므로 persistence.xml에 설정함
admin 유닛을 위한 EntityManager 얻기
@PersistenceContext(unitName="admin")
EntityManager entityManager;
일반적으로 Java EE 모듈은 하나의 지속성 유닛을 가짐
EntityManager 범위설정
범위는 엔티티의 타입에 따라 결정됨(transaction or extended)
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager entityManager;
무상태 세션빈이나 MDB는 확장-지속성 범위를 가질 수 없음
유상태 세션빈은 확장-지속성 범위를 가질 수 있음
- 15 - 과정명 : JPA와 Hibernate
EntityManger 인스턴스생성 : 애플리케이션-관리 EntityManager
애플리케이션-관리 EntityManager
Java-EE 컨테이너로부터 아무것도 원하지 않음
즉, EntityManager의 라이프사이클을 위한 모든 코드를 직접 작성해야 함
Java SE 나 Tomcat과 같은 경량급 웹 컨테이너만 있는 곳에서 사용
Java EE 컨테이너 내에서도 EntityManager에 대한 세심한 통제가 필요한 곳에 사용가능
@Stateless
public class ItemManagerBean implements ItemManager {
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
public ItemManagerBean() {}
@PostConstruct
public void initialize() {
entityManager = entityManagerFactory.createEntityManager();
}
public Item updateItem(Item item) {
entityManager.joinTransaction();
entityManager.merge(item);
return item;
}
@PreDestroy
public void cleanup() {
if (entityManager.isOpen()) {
entityManager.close();
}
}
...
}
- 16 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 엔티티 저장
EntityManager.persist() 인터페이스
Item은 Seller와 다대일 관계를 가지고 있음
persist()는 새로 생성하는 것이지 갱신(update)하는 것이 아님
따라서, persist() 대상 객체의 일차키나 identity가 DB에 존재하지 않아야 함
public Item addItem(String title, String description, byte[] picture, double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
item.setDescription(description);
item.setPicture(picture);
item.setInitialPrice(initialPrice);
Seller seller = entityManager.find(Seller.class, sellerId);
item.setSeller(seller);
entityManager.persist(item);
return item;
}
- 17 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 일차키로 엔티티 검색
EntityManager.find() 인터페이스
일차키로 엔티티 인스턴스 검색
Seller seller = entityManager.find(Seller.class, sellerId);
• 첫번째 파라미터: 엔티티의 자바 타입
• 두번째 파라미터: 엔티티 인스턴스의 identity 값
• identity는 @Id, @IdClass, @EmbeddableId를 이용하여 지정
복합키 사용
SellerPK sellerKey = new SellerPK();
sellerKey.setFirstName(firstName);
sellerKey.setLastName(lastName);
Seller seller = entityManager.find(Seller.class, sellerKey);
검색 결과가 없을 경우 null이나 빈 객체를 리턴함
내부 캐시를 활용함으로써 성능을 높임
데이터 로드 시 두 가지 모드(lazy / eager)를 사용함 @Column(name="PICTURE")
@Lob
@Basic(fetch=FetchType.LAZY)
public byte[] getPicture() {
- 18 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 엔티티 갱신 (1/2)
갱신(update)
EntityManager는 엔티티의 모든 변경을 DB에 반영함
따라서, 애플리케이션은 갱신에 대해 신경쓸 필요 없음
아래 예제에서 seller는 관리상태이므로 DB와 데이터 동기화를 뒤에서 처리하여 줌
public void calculateCreditWorthiness (Long sellerId) {
PowerSeller seller = entityManager.find (PowerSeller.class, sellerId);
seller.setCreditWorth(seller.getCreditWorth()
* CREDIT_FACTOR
* getRatingFromCreditBureauRobberBarons(seller));
seller.setCreditWorth(seller.getCreditWorth()
+ (seller.getCreditWorth()
* FEEDBACK_FACTOR
* seller.getBuyerFeedbackRating()));
seller.setCreditWorth(seller.getCreditWorth()
+ (seller.getCreditWorth()
* SELLING_FACTOR
* getTotalHistoricalSales(seller)));
}
- 19 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 엔티티 갱신 (2/2)
detach/attach 오퍼레이션
EntityManager가 트랜잭션 범위에서 사용될 때, 트랜잭션이 종료되면 detach됨
따라서, 세션빈이 리턴하는 모든 엔티티는 detach 상태임
예, “엔티티 저장”에서 addItem() 메소드가 리턴하는 Item은 detach 상태임
엔티티 갱신을 위해서는 reattacht(== merge) 함 public Item updateItem(Item item) {
entityManager.merge(item);
return item;
}
- 20 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 엔티티 삭제
엔티티 삭제
우선 EntityManager에 merge()한 후 remove()함
현재 attach 상태에 있는 엔티티만 삭제할 수 있기 때문임
Bidder 엔티티가 삭제될 때 BillingInfo 객체를 함께 삭제
일대다 관계에서 다(many)측의 객체를 삭제할 때, 일(one)측의 객체를 함께 삭제할 때 주의를 요함
public void deleteItem(Item item) {
entityManager.remove(entityManager.merge(item));
}
@Entity
public class Bidder {
@OneToOne(cascade=CascadeType.REMOVE)
public BillingInfo setBillingInfo() {
- 21 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : flush()로 갱신 제어
EntityManager.flush()
flush() 를 모를 경우 불리할 수 있음
persist(), merge(), remove() 오퍼레이션 결과가 바로 DB에 반영되지 않음
flush()가 호출될 때까지 반영은 늦추어짐
이러한 메커니즘은 불필요한 DB 접근을 막아서 수행성능을 높이기 위한 것임
flush 모드 – AUTO/COMMIT
디폴트 DB flush 모드는 AUTO 임, EntityManager가 필요할 때 자동으로 flush()호출
트랜잭션 범위 EntityManager의 경우, 트랜잭션 종료 시점에 flush() 호출
확장 범위 EntityManager의 경우, 지속성 컨텍스트가 닫히는 시점에 flush() 호출
반영되지 않은 변경은 다음 질의어 수행 전에 flush() 호출
COMMIT 모드 – 커밋 시에만 flush() 호출
entityManager.setFlushMode(FlushModeType.COMMIT);
모드 변경은 매우 비용이 많이 드는 오퍼레이션 임
entityManager.flush();
- 22 - 과정명 : JPA와 Hibernate
지속성 오퍼레이션 관리 : 엔티티 리프레시
EntityManager.refresh()
DB로부터 관리 중인 모든 엔티티를 다시 읽어옴(repopulate)
undo 오퍼레이션 후에 refresh() 호출은 매우 유익함
refresh() 전에 항상 merge() 함
persist() 오퍼레이션 호출 후 바로 DB에 반영되지 않는 상황에서 사용할 수 있음
public Item undoItemChanges(Item item) {
entityManager.refresh(entityManager.merge(item));
return item;
}
public Item addItem(String title, String description, byte[] picture, double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
...
entityManager.persist(item);
entityManager.flush();
entityManager.refresh(item);
return item;
}
- 23 - 과정명 : JPA와 Hibernate
엔티티 라이프사이클 리스너 : 엔티티 리스너 사용
엔티티 상태 모니터링
Callback 엔티티는 무상태임
예, Item의 입찰금액이 지정한 값을 넘었을 때, 통지하는 경우
리스너 클래스는 DI를 지원하지 않음, 엔티티가 DI 컨테이너 밖에서 존재할 수 있음
public class ItemMonitor {
...
public ItemMonitor() {}
@PrePersist
@PreUpdate
public void monitorItem(Item item) {
if (item.getInitialBidAmount() > ItemMonitor.MONITORING_THRESHOLD) {
notificationManager.sendItemPriceEmailAlert(item);
}
}
}
@Entity
@EntityListeners(actionbazaar.persistence.ItemMonitor.class)
public class Item implements Serializable {
Callback 지정
리스너 등록
- 24 - 과정명 : JPA와 Hibernate
엔티티 라이프사이클 리스너 : 기본 리스너 클래스
감사 또는 트랜잭션 로그
모든 엔티티에 대한 변화를 기록함
이 경우 기본 리스너를 활용할 수 있음, 모든 엔티티의 모든 지속성 오퍼레이션을 로깅
annotation을 이용하여 지정할 법이 없음
persistence.xml을 이용하여 기본 리스너 지정
public class ActionBazaarAuditor {
...
@PrePersist
@PostPersist
...
@PostRemove
public void logOperation(Object object) {
Logger.log("Performing Persistence Operation on: “ + object.getName());
<persistence-unit name="actionBazaar">
...
<default-entity-listeners>
actionbazaar.persistence.ActionBazaarAuditor.class
</default-entity-listeners>
...
- 25 - 과정명 : JPA와 Hibernate
엔티티 라이프사이클 리스너 : 리스너 클래스 실행순서
실행 순서
기본 리스너, 엔티티 클래스 특정 리스너, 부모 클래스 리스너 등이 존재함
기본 리스너가 가장 먼저 실행됨, 다음으로 부모 클래스 리스너, ...
동일한 유형의 리스너가 여러 개 일 경우 나열된 순서대로 실행
실행 순서는 프로그램으로 제어할 수 없지만, 기본 리스너와 부모 리스너를 제외가능
EntityListeners({actionbazaar.persistence.
ItemMonitor.class, actionbazaar.persistence.
ItemMonitor2.class})
@Entity
@ExcludeDefaultListeners
@ExcludeSuperClassListeners
@EntityListeners(actionbazaar.persistence.SellerMonitor.class)
public class Seller extends User {
- 26 - 과정명 : JPA와 Hibernate
엔티티 운영 가이드
컨테이너-관리 엔티티 관리자를 사용할 것
EntityManager를 웹-티어로 주입(injecting)하지 말 것
엔티티 접근 객체 패턴을 사용할 것
콜백을 외부 리스너와 분리할 것
5.1 상속 매핑
5.2 EntityManager
5.3 질의API
5.4 JPQL
5일차 – JPA
질의 API소개
질의 실행
- 28 - 과정명 : JPA와 Hibernate
질의 API
질의 API 소개 : 개요
지금까지 EntityManager.find를 이용하여 엔터티를 검색하였으며, 이는 ID나 일차키로 엔터티를 검색하는 것임
질의 API는 최적화된 질의어를 작성할 수 있게 해줌
EntityManager의 인터페이스와 java.persistence.Query 인터페이스를 이용하여 질의어 정의, 파라미터 바인딩, 실행, 페이지 처리 등을 수행함
JPA 질의 API는 JPQL이나 SQL 모두를 사용하여 질의를 작성할 수 있음
SQL 보다는 JPQL에 집중할 예정임
SQL은 레코드를 리턴하지만, JPQL은 엔티티를 리턴함
EntityManager query methods
Query interface
JPQL
JDBC 질의 단계(SQL) JPA 질의 단계(JPQL)
1. DB 커넥션 획득 1. EntityManager 인스턴스 획득
2. 질의문 생성 2. 질의 인스턴스 생성
3. 질의문 실행 3. 질의 실행
4. 결과검색(DB 레코드) 4. 결과 엔터티 검색
- 29 - 과정명 : JPA와 Hibernate
질의 API 소개 : 질의(query) 분석
질의(query) 타입
지명(named) 질의: 저장한 후 재사용함
동적(dynamic, or ad hoc) 질의: 실행 시점에 다양한 환경에 맞추어 생성됨
동적 질의 예
모든 카테고리를 검색하고자 함, JPQL 이용
지명 질의일 경우: em.createNamedQuery() 호출
@PersistenceContext em; EntityManager 주입
...
public List findAllCategories() {
Query query = em.createQuery("SELECT c FROM Category c"); ...
return query.getResultList();
}
- 30 - 과정명 : JPA와 Hibernate
질의 API 소개 : 지명(named) 질의 (1/2)
개요
사용하기 전에 미리 정의해야 함
annotation을 이용하거나 Xml 메타데이터를 이용하여 정의할 수 있음
지명질의는 인스턴스를 만들 때 이름을 이용하여 접근함
지명 질의의 장점
질의의 재사용을 높임
코드의 유지보수를 용이하게 함, 질의가 비즈니스 로직에 흩어지지 않음
수행성능을 높임, 한 번 준비되면 효율적으로 재사용됨
annotation을 사용한 지명 질의의 예
@Entity
@NamedQuery(
name = "findAllCategories",
query = "SELECT c FROM Category c WHERE c.categoryName
LIKE :categoryName ")
public class Category implements Serializable {
...
}
- 31 - 과정명 : JPA와 Hibernate
질의 API 소개 : 지명(named) 질의 (2/2)
여러 개의 지명 질의
javax.persistence.NamedQueries 주석(annotation) 사용
지속성 유닛 범위이므로 범위 내에서 질의 이름이 유일해야 함
@Entity
@NamedQueries({
@NamedQuery(
name = "findCategoryByName",
query = "SELECT c FROM Category c WHERE c.categoryName
LIKE :categoryName order by c.categoryId"
),
@NamedQuery(
name = "findCategoryByUser",
query = "SELECT c FROM Category c JOIN c.user u
WHERE u.userId = ?1"
)})
@Table(name = "CATEGORIES")
public class Category implements Serializable {
}
- 32 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인스턴스 생성 (1/2)
EntityManager 인터페이스
질의 인스턴스를 생성하기 위한 메소드 제공
원시 SQL 질의 생성을 위한 메소드도 제공
지명 질의 인스턴스 생성
엔티티가 속한 지속성 유닛에 접근하는 모든 컴포넌트로부터 지명 질의 인스턴스 생성
오픈 상태의 EntityManager 인스턴스가 있어야 함
사용하려면 EntityManager.createNamedQuery() 메소드를 호출함
• Query queyr = em.createNamedQuery(“findAllCategories”);
메소드 시그너처 설명
public Query createQuery(String jpqlString); JPQL 문을 이요하여 동적 질의 생성
public Query createNamedQuery(String name); 질의 인스턴스 생성
public Query createNativeQuery(String sqlString); public Query createNativeQuery(String sqlString, Class result Class); public Query createNativeQuery(String sqlString, String resultSetMapping);
원시 SQL문을 이용하여 동적 질의 생성
- 33 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인스턴스 생성 (2/2)
동적 질의 인스턴스 생성
EntityManager가 가용한 곳 어디서든지 동적 질의 생성 가능함
• 세션빈, MDB, 웹 애플리케이션, 컨테이너 외부
• EJB 2 에서는 동적 질의를 지원하지 않음
질의 생성: EntityManager.createQuery()
• 타당한 JPQL 문을 파라미터로 전달
EntityManager가 컨테이너-관리든 애플리케이션-관리든 상관없음
질의 생성 예
• Query query = em.createQuery(“SELECT i FROM Item i”);
JPQL은 SQL과 유사하지만 JPQL 사용를 권장함
- 34 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인터페이스 사용 (1/5)
질의 인터페이스
질의 실행을 위한 메소드 정의
질의 인스턴스를 위한 파라미터 설정 메소드 정의
페이지 처리, 플러시 모드 제어 등을 위한 메소드 정의
SQL과 JPQL은 동일한 인터페이스 사용
메소드 시그너처 설명
public List getResultList() 질의 결과 세트 검색
public Object getSingleResult() 단일 결과나 객체 검색
public int executeUpdate() JPQL UPDATE나 DELETE 문 실행
public Query setMaxResults(int maxResult) 검색할 객체의 최대 갯수
public Query setFirstResult(int startPosition) 첫번째 질의 결과의 첫번째 위치
public Query setHint(String hintName, Object value) 질의를 위한 벤더 특정 힌트 설정
public Query setParameter(String name, Object value) 지명 파라미터를 위한 값 설정
public Query setParameter(String name, Date value, TemporalType temporalType)
파라미터가 Date 타입일 경우, 지면 파라미터 값 설정
... ...
- 35 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인터페이스 사용 (2/5)
질의 인터페이스 사용 예,
미리 정의한 지명 질의로부터 질의 인스턴스 생성함
파라미터 설정
특정 가격을 가진 모든 Item 엔티티의 인스턴스 검색
• SELECT i FROM Item i WHERE i.initialPrice = ?1
파라미터는 이름이나 숫자로 지정이 가능함
• query.setParameter(1, 100.0);
여러 파라미터 설정
• SELECT i FROM Item i WHERE i.initialPrice > ?1 AND i.initialPrice < ?2
• query.setParameter(1, 100.0);
• query.setParameter(2, 200.0);
query = em.createNamedQuery("findCategoryByName");
query.setParameter("categoryName", categoryName);
query.setMaxResults(10);
query.setFirstResult(3);
List categories = query.getResultList();
- 36 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인터페이스 사용 (3/5)
지면 파라미터 설정 - 코드 가독성을 높여 줌
• SELECT i FROM Item i WHERE i.initialPrice = :price
• query.setParameter(“price”, 100.0);
단일 엔터티 검색
하나의 엔티티만 검색
• query.setParameter(1, “Recycle from Mr. Dumpster”);
• Category cat = (Category)query.getSingleResult();
결과가 없을 경우, NoResultException
결과가 여러 개일 경우, NonUniqueResultException try {
...
query.setParameter(1, "Recycle from Mr. Dumpster");
Category cat = (Category)query.getSingleResult();
...
}catch (NonUniqueResultException ex) {
handleException(ex);
} catch (NoResultException ex) {
handleException(ex);
}
- 37 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인터페이스 사용 (4/5)
여러 엔티티 검색
대부분의 질의는 결과 집합(set)이나 결과 리스트를 리턴함
100과 200 사이의 결과를 검색하는 질의
query.setParameter("lowPrice", lowPriceValue) 지명 파라미터 lowPrice
query.setParameter("highPrice", highPriceValue)
List items = query.getResultList();
결과 리스트가 없을 경우 빈 리스트를 리턴함, 예외를 던지지 않음
결과 리스트의 페이지 처리
수천 또는 수만 건의 검색 결과를 효율적으로 처리하는 방법이 필요함
JPA는 페이지 처리 인터페이스를 제공함
query.setMaxResults(50);
query.setFirstResult(0); 시작 오프셋 값
List items = query.getResultList();
다음 50 건을 가져오려면,
query.setMaxResults(50);
query.setFirstResult(50);
- 38 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 인터페이스 사용 (5/5)
오프셋과 페이지 사이즈를 동적으로 처리
질의 flush 모드 통제
flush 모드를 통해 EntityManager가 DB에 쓰는 방식을 결정
AUTO 모드(기본): 지속성 컨텍스트 안의 엔티티 갱신을 지속성 공급자가 책임 짐
COMMIT 모드: 지속성 컨텍스트 안의 엔티티에 대한 갱신을 정의하지 않음
대부분의 경우 AUTO 모드 사용을 권장함
public List getPagedItems(int pageIndex, int pageSize) {
...
query.setMaxResults(pageSize) ;
query.setFirstResult(pageIndex) ;
return query.getResultList();
}
- 39 - 과정명 : JPA와 Hibernate
질의 실행 : 질의 힌트 지정
벤더 고유의 확장
질의 실행 중에 사용할 수 있는 벤더 고유의 확장 기능이 있음
확장 기능의 예, 성능 최적화, 질의 힌트 전달
질의 힌트
질의 힌트는 지속성 제공자가 질의 수행 중에 사용할 팁
예, 질의 사용 중에 캐시를 사용할 것을 지정함
TopLink 사용 시 타임아웃 시간을 10초로 설정함
• query.setHint(“toplink.jdbc.timeout”, new Integer(10000));
Hibernate 사용 시 동일한 동작
• query.setHime(“org.hibernate.timeout”, new Integer(10));
공급자의 파라미터 지정방식에 따름, 다음은 자주 쓰이는 예
• 로우 패치 크기, 캐시 모드, 캐시 리프레시, 타임아웃 @NamedQuery(
name = "findUserWithNoItems",
query = "SELECT DISTINCT u FROM User u WHERE u.items is EMPTY",
hints = { @QueryHint(name = "org.hibernate.timeout", value = "10") }
)
5.1 상속 매핑
5.2 EntityManager
5.3 질의API
5.4 JPQL
5일차 – JPA
개요
문(statement) 유형 정의
FROM절 사용
조건식과 연산자
JPQL 함수 사용
SELECT절 사용
조합(aggregation)사용
질의 결과 정렬
하위-질의 사용
엔티티조인
대량 갱신과 삭제
- 41 - 과정명 : JPA와 Hibernate
개요
JPQL(Java Persistence Query Language)
Hibernate는 HSQL 제공
Kodo는 JDO QL 제공
JPQL은 EJB 2의 EJB QL의 확장판임
JPQL은 자바 영역 안에서 클래스와 객체를 다룸
SQL은 DB 영역에서 테이블, 컬럼, 로우를 다룸
둘은 외관상 비슷하지만 완전히 서로 다른 두 영역에서 실행 됨
JPQL이 변환을 통해 SQL로 변경되는 절차
- 42 - 과정명 : JPA와 Hibernate
문(statement) 유형 정의 (1/3)
JPQL은 세 가지 문(statement)을 제공함
SELECT: 엔티티와 엔티티 관련 데이터를 검색함
UPDATE: 하나 또는 그 이상의 엔티티를 갱신함
DELETE: 하나 또는 그 이사의 엔티티를 삭제함
SELECT 정의 및 사용
JPQL의 예,
SELECT 절: 검색할 객체 타입, 엔티티, 값 등을 지정함
FROM 절: 다른 절에서 사용할 엔티티 선언
[옵션] WHERE 절: 질의 결과를 필터링 함
[옵션] ORDER BY 절: 질의 결과 순서를 정함
[옵션] GROUP BY 절: 조합(aggregation) 수행
[옵션] HAVING 절: 조합과 결합(conjunction) 안에서 필터링 수행
SELECT c
FROM Category c
WHERE c.categoryName LIKE :categoryName
ORDER BY c.categoryId
- 43 - 과정명 : JPA와 Hibernate
문(statement) 유형 정의 (2/3)
UPDATE와 DELETE 정의
WHERE 절에 조건을 지정함으로써 대규모 갱신 및 삭제가 가능함
SQL 문과 매우 유사함
UPDATE 사용
한 가지 엔티티 유형만 지정할 수 있음
엔티티 개수를 제한하기 위해 WHERE 절을 사용함
UPDATE 문의 구문,
성이 Packrat인 판매자의 상태를 G(Gold)로 하고 커미션비율을 10 퍼센트로 함
UPDATE entityName indentifierVariable
SET single_value_path_expression1 = value1, ...
single_value_path_expressionN = valueN
WHERE where_clause
UPDATE Seller s
SET s.status = 'G', s.commissionRate = 10
WHERE s.lastName like 'PackRat%'
- 44 - 과정명 : JPA와 Hibernate
문(statement) 유형 정의 (3/3)
DELETE 사용
SQL 문과 매우 비슷함
하나의 엔티티 유형만 지정할 수 있음
WHERE 절에서 문의 영향을 받는 대상을 제한함
DELETE문의 구문
Silver 상태의 판매자를 모두 삭제함
DELETE entityName indentifierVariable
WHERE where_clause
DELETE Seller s
WHERE s.status= ‘Silver’
- 45 - 과정명 : JPA와 Hibernate
FROM 절 사용 (1/4)
FROM 절
가장 중요한 절로 질의를 위한 도메인(질의 대상 엔티티)을 결정함
• FROM Category c
• Category는 도메인이며, c는 Category 타입에 대한 식별자(identifier)로 지정함
질의 도메인 지정: 엔티티 지명
@Entity 주석에서 name 요소를 사용하여 엔티티의 이름을 정의할 수 있음
name을 지정하지 않을 경우, 엔티티 클래스의 이름이 엔티티 이름이 됨
지속성 유닛 안에서 이름은 유일해야 함
Category 클래스에서 엔티티 이름 정의 예,
이 경우, FROM 절은 “FROM CategoryEntity c”
@Entity(name = "CategoryEntity")
public class Category
- 46 - 과정명 : JPA와 Hibernate
FROM 절 사용 (2/4)
식별자(identifier) 변수
(SELECT c )FROM Category c 에서 정의된 식별자 c는 다른 절에서도 사용함
구문
FROM entityName [AS] identificationVariable
identificationVariable는 자바에서 타당한 변수여야 하며, JPQL의 예약어가 아니어야 함
다음은 JPQL의 예약어들임 유형 예약어
문(statement)과 절(clause) SELECT, UPDATE, DELETE, FROM, WHERE, GROUP, HAVING, ORDER, BY, ASC, DESC
조인 JOIN, OUTER, INNER, LEFT, FETCH
조건과 연산 DISTINCT, OBJECT, NULL, TRUE, FALSE, NOT, AND, OR, BETWEEN, LIKE, IN, AS, UNKNOWN, EMPTY, MEMBER, OF, IS, NEW, EXISTS, ALL, ANY, SOME
함수(function) AVG, MAX, MIN, SUM, COUNT, MOD, UPPER, LOWER, TRIM, POSITION, CHARACTER_LENGTH, CHAR_LENGTH, BIT_LENGTH, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP
- 47 - 과정명 : JPA와 Hibernate
FROM 절 사용 (3/4)
경로 표현식(path expression) 이란 ?
표현식 c.categoryName, c.categoryId 등을 경로 표현식이라고 함
(.)은 항해 연산자
WHERE 절이나 ORDER BY 절에서 사용함
연관관계 필드는 단일 값 객체거나 집합 객체일 수 있음
컬렉션 값 표현식의 예,
컬렉션 값 표현식을 이용한 지속성 필드 항해 예,
• c.items.user.firstName
• c.items.user.contactDetails.email
• c.items.itemName (== category.getItems().getItemName() 와 동일함)
SELECT distinct c
FROM Category c
WHERE c.items is NOT EMPTY
- 48 - 과정명 : JPA와 Hibernate
FROM 절 사용 (4/4)
WHERE 를 이용한 필터링
WHERE 절은 질의 결과를 필터링 함
WHERE 절이 없을 경우, 모두를 대상으로 함
조건을 지정함
WHERE 절에는 자바 상수의 거의 모든 타입 사용, boolean, float, enum, String, int 등
octal, hexadecimal, byte[], char[] 등은 사용하지 못함
SELECT c
FROM Category c
SELECT c
FROM Category c
WHERE c.categoryId > 500
- 49 - 과정명 : JPA와 Hibernate
조건식과 연산자 (1/5)
개요
WHERE 절의 조건은 조건 표현식 또는 조건식(conditional expression)이라고 함
JPQL은 숫자, 문자열, 부울리언 값, 경로 표현식을 관계형 연산자를 이용하여 평가함
조건식의 예,
c.categoryName = ‘Dumped Cars’
연산자의 유형들
조건식의 예,
연사자 유형 연산자
항해(navigational) .
단항 부호 (unary sign) +, -
수식(arithmetic) *, /, +, -
관계(relational) =, >, >=, <, <=, <>, [NOT] BETWEEN, [NOT] LIKE, [NOT] IN, IS [NOT] NULL, IS [NOT] EMPTY, [NOT] MEMBER [OF]
논리(logical) NOT, AND, OR
WHERE c.categoryName = 'Dumped Cars'
OR c.categoryName = 'Furniture from Garbage'
- 50 - 과정명 : JPA와 Hibernate
조건식과 연산자 (2/5)
BETWEEN을 이용한 범위 비교
수식에서 값의 범위를 비교하기 위해 BETWEEN을 사용함
BETWEEN 연산자 구문
path_expression [NOT] BETWEEN lowerRange and upperRange
범위 표현의 예,
WHERE c.categoryId BETWEEN :lowRange AND :highRange
IN 연산자 사용
경로 표현식이 리스트 값 안에 있는 지 여부를 판단하는 조건식에 IN을 사용함
IN 연산자 구문,
path_expression [NOT] IN (List_of_values)
IN 연산자를 사용한 예<
• WHERE u.userId IN (‘viper’, ‘drdba’, ‘dumster’)
• WHERE u.userId NOT IN (‘viper’, ‘drdba’, ‘dumster’)
하위 질의와 IN의 사용, (하위 질의 결과가 복수일 수 있음)
WHERE c.user IN (SELECT u FROM User u WHERE u.userType = 'A')
- 51 - 과정명 : JPA와 Hibernate
조건식과 연산자 (3/5)
LIKE 연산자 사용
단일값 경로 표현식이 문자열 패턴과 일치하는 지 확인할 때 LIKE 연산자를 사용함
LIKE 연산자 구문
string_value_path_expression [NOT] LIKE pattern_value
• pattern_value는 상수이거나 파라미터임
• pattern_value는 (_)나 (%)를 포함할 수 있음, (_)는 단일 문자, (%)는 여러 문자를 의미함
LIKE 연산자를 사용한 예,
WHERE c.itemName LIKE ‘_ike’ mike, bike 모두 해당
(%)를 사용한 예,
WHERE c.categoryName LIKE ‘Recycle%’ Recycle로 시작하는 모든 단어
(%)를 앞뒤로 사용한 예,
WHERE c.categoryName NOT LIKE ‘%Recycle%’ Recycle이 포함되지 않음 모든 이름
파라미터를 적용한 예,
WHERE c.categoryName NOT LIKE ?1
- 52 - 과정명 : JPA와 Hibernate
조건식과 연산자 (4/5)
널 값과 빈 컬렉션 다루기
널과 빈 문자열은 서로 다르고, JPQL은 서로 다른 방식으로 이들을 다룸
널과 빈 문자열을 동일한 방식으로 다루는 DB도 있음
빈 문자열과 널을 비교해서 true를 리턴하는 지 확인해야 함
널을 포함한 부울리언 연산 결과
NOT NULL 체크 예,
WHERE c.parentCategory IS NOT NULL
표현식 1 값 부울리언 연산자 표현식 2 값 결과
TRUE AND null UNKNOWN
FALSE AND null FALSE
Null AND null UNKNOWN
TRUE OR null TRUE
Null OR null UNKNOWN
FALSE OR null UNKNOWN
NOT null UNKNOWN
- 53 - 과정명 : JPA와 Hibernate
조건식과 연산자 (5/5)
컬렉션
컬렉션의 IS NOT NULL 체크가 불가능하여, IS [NOT] EMPTY를 사용함
컬렉션 EMPTY 체크 예,
WHERE c.items IS EMPTY
JPQL에서의 다음 표현이,
SQL의 다음 표현으로 변환됨
SELECT c
FROM Category c
WHERE c.items IS EMPTY
SELECT
c.CATEGORY_ID, c.CATEGORY_NAME, c.CREATE_DATE,
c.CREATED_BY, c.PARENT_ID
FROM CATEGORIES c
WHERE (
(SELECT COUNT(*)
FROM CATEGORIES_ITEMS ci, ITEMS i
WHERE (
(ci.CATEGORY_ID = c.CATEGORY_ID) AND
(i.ITEM_ID = ci.ITEM_ID))) = 0)
- 54 - 과정명 : JPA와 Hibernate
JPQL 함수 사용 (1/2)
개요
JPQL은 문자열과 산술(arithmetic) 연산을 위한 내장 함수를 제공함
이 함수는 WHERE절이나 HAVING 절에서 사용할 수 있음
문자열 함수
질의 결과 필터링에 사용함
문자열 함수 설명
CONCAT(string1, string2) 두 문자열 값을 합쳐서 리턴함
SUBSTRING(string, position, length) position부터 length까지의 부분 문자열을 리턴함
TRIM([LEADING|TRAILING|BOTH] [trim_character] FROM] string_to_trimmed)
지정된 문자열을 새로운 길이로 정리함. 정리(trimming)은 LEADING, TRAILING, 또는 BOTH 끝단에서. 정리 문자가 없으면 기본으로 스페이스임
LOWER(string) 문자열을 소문자로 변환
UPPER(string) 문자열을 대문자로 변환
LENGTH(string) 문자열의 길이를 리턴함
LOCATE(searchString, sringToBeSearched[initialPosition])
주어진 문자열의 위치를 리턴함. initialPosition을 주지 않으면 1로부 검색을 시작함
- 55 - 과정명 : JPA와 Hibernate
JPQL 함수 사용 (2/2)
문자열 함수 (계속)
합친 문자열을 비교하는 예,
WHERE CONCAT(u.firstName, u.lastName) = ‘ViperAdmin’
하위 문자열을 비교하는 예,
WHERE SUBSTRING(u.lastName, 1, 3) = ‘VIP’
산술 함수
CRUD 오퍼레이션에 계산은 별로 쓰이지 않음
보고 목적으로 산술 함수를 사용하면 매우 유용함
다음 함수는 WHERE 절이나 HAVING 절에서 사용함
SIZE의 예, WHERE SIZE(c.items) = 5
산술 함수 설명
ABS(simple_arithmetic_expression) 절대값을 리턴함
SQRT(simple_arithmetic_expression) 제곱근을 리턴함
MOD(num, div) 정수값 리턴
SIZE(collection_value_path_expression) 컬렉션의 항목 개수를 리턴함
- 56 - 과정명 : JPA와 Hibernate
SELECT 절 사용
개요
SELECT절은 질의 결과를 나타냄
SELECT절의 구문
• SELECT [DISTINCT] expression1, expression2, .... expressionN
• expression은 단일 값임, 컬렉션 값 경로 표현식은 불가능함
SELECT 절의 예,
중복 데이터를 허용하지 않는 예,
생성자 표현식 사용
하나 이상의 자바 인스턴스를 리턴하기 위해 생성자 사용이 가능함
SELECT c.categoryName, c.createdBy
FROM Category c
SELECT DISTINCT c.categoryName, c.createdBy
FROM Category c
SELECT NEW actionbazaar.persistence.ItemReport (c.categoryID, c.createdBy)
FROM Category
WHERE categoryId.createdBy = :userName
- 57 - 과정명 : JPA와 Hibernate
조합(Aggregation) 사용 (1/2)
조합은 엔티티 컬렉션을 다루는 보고서 질의를 작성할 때 유용함
조합 함수
JPQL은 조합 함수를 제공함, AVG, COUNT, MAX, MIN, SUM
조합함수의 리턴타입
• AVG() 리턴타입은 Double
• COUNT() 리턴타입은 Long
• MAX() 리턴타입은 지속성 필드에 따라 다름
• MIN() 리턴타입은 지속성 필드에 따라 다름
• SUM() 리턴타입은 Long 이나 Double
가격이 가장 높은 값을 찾는 예,
질의 결과 개수를 세는 예,
SELECT MAX(i.itemPrice)
FROM Item i
SELECT COUNT(c)
FROM Category c
- 58 - 과정명 : JPA와 Hibernate
조합(Aggregation) 사용 (2/2)
GROUP BY와 HAVING으로 묶음짓기
특정 필드를 기준으로 데이터를 묶음지을 필요가 있음
User와 Category 간에 일대다 관계가 있을 때, Category 인스턴스를 user기준으로 묶음
위의 예에서, Category 엔티티를 다섯 개 이상 가진 사용자만으로 제한한 예,
WHERE 절 추가 한 예,
SELECT c.user, COUNT(c.categoryId)
FROM Category c
GROUP BY c.user
SELECT c.user, COUNT(c.categoryId)
FROM Category c
GROUP BY c.user
HAVING COUNT(c.categoryId) > 5
SELECT c.user, COUNT(c.categoryId)
FROM Category c
WHERE c.createDate is BETWEEN :date1 and :date2
GROUP BY c.user
HAVING COUNT(c.categoryId) > 5
- 59 - 과정명 : JPA와 Hibernate
질의 결과 정렬
ORDER BY 절
검색 결과 값이나 객체를 정렬할 때 사용함
ORDER BY 절 구문, ASC 이 기본값임
ORDER BY path_expression1 [ASC | DESC], ... path_expressionN [ASC | DESC]
카테고리 이름으로 오름차순으로 정렬한 예,
오름차순과 내림차순을 각각 지정한 예,
WHERE 절이 있을 경우, 먼저 WHERE 절에 의해 필터링 된 다음, 정렬함
SELECT c
FROM Category c
ORDER BY c.categoryName ASC
SELECT c.categoryName, c.createDate
FROM Category c
ORDER BY c.categoryName ASC, c.createDate DESC
- 60 - 과정명 : JPA와 Hibernate
하위-질의 사용 (1/3)
하위-질의(subquery)
하위-질의는 질의 속의 질의임
WHERE 절이나 HAVING 절에서 하위-질의를 사용할 수 있음
JPQL에서는 SQL과는 달리 FROM 절에서는 하위-질의를 사용할 수 없음
하위-질의가 먼저 실행되고 본 질의가 다음으로 실행됨
하위-질의 구문
[NOT] IN / [NOT] EXISTS / ALL / ANY / SOME (하위-질의)
IN에서 하위-질의
IN절은 리스트 값에서 하나의 값이 포함되어 있는지를 평가함
IN에서 하위-질의 예,
SELECT i
FROM Item i
WHERE i.user IN (SELECT c.user
FROM Category c
WHERE c.categoryName LIKE :name)
- 61 - 과정명 : JPA와 Hibernate
하위-질의 사용 (2/3)
EXISTS
하위-질의가 어떤 결과 세트를 포함하는 지 확인 함
EXISTS 절의 예,
EXISTS 절은 IN 연산자와 동일함
테이블이 대용량 데이터를 가지고 있을 경우, IN 보다는 EXISTS 사용을 권장함
DB는 EXISTS를 사용할 때 더 효율적으로 처리함
ANY, ALL, SOME
IN 연산자 사용과 유사함
산술 연산자와 함께 사용할 수 있음, =, >, >=, <, <=, <>
SELECT i
FROM Item i
WHERE EXISTS (SELECT c
FROM Category c
WHERE c.user = i.user)
- 62 - 과정명 : JPA와 Hibernate
하위-질의 사용 (3/3)
ANY, ALL, SOME (계속)
하위-질의와 ALL 연산자의 예,
하위-질의와 ANY 연산자의 예,
SOME은 ANY의 다른 이름
SELECT c
FROM Category c
WHERE c.createDate >= ALL
(SELECT i.createDate
FROM Item i
WHERE i.user = c.user)
SELECT c
FROM Category c
WHERE c.createDate >= ANY
(SELECT i.createDate
FROM Item i
WHERE i.seller = c.user)
- 63 - 과정명 : JPA와 Hibernate
엔티티 조인 (1/3)
JOIN 연산자
FROM 절에 엔티티 지정함
WHERE 절에 조인 조건을 지정함
두 엔티티는 관계나 임의의 지속성 필드를 기반으로 연결(join)함
내부 조인: 관계를 이용하여 Category와 Item을 조인하고 조인 조건에 일치하는 엔티티만을 검색함
외부 조인: 조인 조건에 일치하는 결과 뿐 아니라 다른 쪽의 엔티티에 일치하지 않는 엔티티 역시 검색함, 즉 Item과 일치하지 않더라도 Category의 모든 인스턴스를 검색함
쎄타(Theta) 조인
관계 보다는 임의의 지속성이나 관계 필드를 기반으로 연결함
Category의 rating 필드가 DELUXE, GOLD, STANDARD, PREMIUM 값을 가짐
Item의 star 필드 역시 DELUXE, GOLD, STANDARD, PREMIUM 값을 가짐
이 두 엔티티를 쎄타 조인을 걸면, SELECT i
FROM Item i, Category c
WHERE i.star = c.rating
- 64 - 과정명 : JPA와 Hibernate
엔티티 조인 (2/3)
관계 조인
가장 흔한 형태의 조인임
관계를 바탕으로 둘 또는 그 이상의 엔티티를 연결함
Category와 User는 다대일 관계를 가짐, 특정 범주에 속하는 모든 사용자 검색 예,
외부 조인
엔티티 간의 연관관계가 선택적일 때, 조인 조건에 맞지 않는 추가 엔티티를 검색할 수 있음
보고서 작성에 매우 유용함
Category를 가지지 않는 User도 있을 경우의 예,
SELECT u
FROM User u INNER JOIN u.Category c INNER 절은 선택사항임
WHERE u.userId LIKE ?1
SELECT u
FROM User u LEFT OUTER JOIN u.Category c
WHERE u.userId like ?1
- 65 - 과정명 : JPA와 Hibernate
엔티티 조인 (3/3)
페치(fetch) 조인
특정 엔티티를 위한 질의를 하면서, 동시에 연관 엔티티도 동시에 검색할 수 있음
Bid를 검색할 때, 연관된 Bidder의 인스턴스를 로드하고 초기화 하는 예,
관계에 대해 지연 로드로 설정된 상황, 특정 질의에서 연관 엔티티를 즉시 로드할 때
페치 조인은 외부,내부 조인과 함께 사용할 수 있음
SELECT b
FROM Bid b FETCH JOIN b.bidder
WHERE b.bidDate >= :bidDate
- 66 - 과정명 : JPA와 Hibernate
대량 갱신과 삭제
개요
연말에 사용자의 상태 값을 모두 G(old)로 변경하는 예,
특정 조건에 맞는 사용자를 모두 삭제하는 예,
대량 갱신과 삭제는 여러 함정이 있으므로 반드시 별도의 트랜잭션으로 실행해야 함
DB 오퍼레이션으로 바로 변환되므로 관리 엔티티와 DB 간 불일치 발생 가능함
UPDATE User u
SET u.status = 'G'
WHERE u.numTrades >=?1
@PersistenceContext em;
. . .
// start transaction
Query query = em.createQuery("DELETE USER u WHERE u.status = :status ");
query.setParameter("status", 'GOLD');
int results = query.executeUpdate();
//end transaction
- 67 - 과정명 : SQL기초와 MyBatis – SQL/MyBatis
넥스트리소프트(주) 박석재 수석 ([email protected]) 임병인 수석 ([email protected])