Batch 처리
Hibernate를 사용하여 데이터베이스 내에서 100 000 개의 행들을 삽입시키는 본래의 접근법은 다음과 같다:
이것은 50 000번째 행 가까운 곳에서 OutOfMemoryException으로 떨어질 것이다. 그것은 Hibernate가
session-level 캐시 속에 모든 새로이 삽입된 Customer 인스턴스들을 캐시시키기 때문이다.
이 장에서 우리는 이 문제를 피하는 방법을 당신에게 보여줄 것이다. 하지만 먼저 당신이 배치 처리를 행하는 중이라면, 당신이 적당한 퍼포먼스를
성취하려고 할 경우에 당신이 JDBC 배치 사용을 가능하게 하는 것은 절대적으로 필요하다. JDBC 배치 사이즈를 적당한 숫자(10-50)로 설정하라:
당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다:
You also might like to do this kind of work in a process where interaction with
the second-level cache is completely disabled:
Batch inserts
새로운 객체들을 영속화 시킬 때, 당신은 first-level 캐시의 사이즈를 제어하기 위해 세션을 정기적으로 flush()
시키고 나서 clear() 시켜야 한다.
Batch updates
데이터 검색과 업데이트의 경우 동일한 개념들이 적용된다. 게다가 당신은 많은 데이터 행들을 반환하는 질의들에 대해 서버-측 커서들의 장점을
취하는데 scroll()을 사용할 필요가 있다.
DML-스타일 연산들
이미 논의했듯이, 자동적이고 투명한 객체/관계형 매핑은 객체 상태에 대한 관리에 관계된다. 이것은 객체 상태가 메모리 내에서 이용 가능함을
의미하므로, (SQL Data Manipulation Language(DML) 문장들 : INSERT,
UPDATE, DELETE를 사용하여) 데이터베이스에서 직접 데이터를
업데이트하거나 삭제하는 것은 메모리 내 상태에 영향을 주지 않을 것이다. 하지만 Hibernate는 Hibernate Query Language
(HQL)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다.
UPDATE와 DELETE 문장들의 유사-구문은 다음과 같다:
( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?. 노트할 몇 가지 :
from-절에서, FROM 키워드는 옵션이다
from-절 내에 한 개의 명명된 엔티티가 오직 존재할 수 있다; 그것은 선택적으로 alias될 수 있다. 만일 엔티티
이름이 alias되면, 그때 임의의 프로퍼티 참조들은 그 alias를 사용하여 수식되어야 한다; 만일 엔티티 이름이
alias되지 않을 경우, 임의의 프로퍼티 참조들에 대해 수식되는 것은 규칙에 어긋난다.
join들은 (함축적이든 명시적이든) 대량 HQL 질의 속에 지정될 수 없다. 서브-질의들이 where-절에 사용될 수 있다;
서브질의들 그 자신들은 조인들을 포함할 수 있다.
where-절 또한 옵션이다.
하나의 예제로서, 한 개의 HQL UPDATE를 실행하기 위해, Query.executeUpdate()
메소드(이 메소드는 JDBC의 PreparedStatement.executeUpdate()와 유사하게 명명된다)를 사용하라:
한 개의 HQL DELETE를 실행하기 위해, 동일한 Query.executeUpdate() 메소드를
사용하라:
Query.executeUpdate() 메소드에 의해 반환되는 int 값은 그 오퍼레이션에 의해
영향받은 엔티티들의 개수를 나타낸다. 이것이 데이터베이스 내에서 영향받은 행들의 개수와 상관이 있는지 없는지 여부를 살펴보자. HQL
대량 오퍼레이션은 예를 들어 joined-subclass의 경우에 실행 중인 여러 개의 실제 SQL 문장들로 귀결될 수 있다. 반환되는 숫자는
그 문장에 의해 영향받은 실제 엔티티들의 개수를 나타낸다. joined-subclass 예제로 되돌아가면, 서브 클래스들 중 하나에 대한 삭제는
단지 그 서브클래스가 매핑되어 있는 테이블에 대한 삭제 뿐만 아니라 또한 "루트" 테이블과 상속 계층에서 더 내려온 잠정적으로
조인된-서브클래스 테이블들에 대한 삭제들로 귀결될 수 있다.
장래의 배포본들에서 전달될 대량 HQL 오퍼레이션들에 대한 몇 가지 제한들이 현재 존재함을 노트하라; 상세한 것은 JIRA 로드맵을 참조하라.
INSERT 문장들을 위한 유사-구문은 다음과 같다:
INSERT INTO EntityName properties_list select_statement. 노트할 몇 가지:
오직 INSERT INTO ... SELECT ... 형식 만일 지원된다; INSERT INTO ... VALUES ... 형식은 지원되지 않는다.
properties_list는 SQL INSERT 내에서 column speficiation과 유사하다.
매핑된 상속에 참여하는 엔티티들의 경우, 그 주어진 클래스-레벨 상에 직접 정의된 프로퍼티들 만이 properties_list에 사용될 수 있다.
슈퍼클래스 프로퍼티들은 허용되지 않는다; 그리고 서브클래스 프로퍼티들은 의미가 없다. 달리 말해 INSERT 문장들은
본래적으로 다형적이지 않다.
select_statement는 반환 타입들이 insert에 의해 기대되는 타입들과 일치해야 한다는 단서 하에 임의의 유효한 HQL select 질의일 수
있다. 현재 이것은 체크를 데이터베이스로 이관시키는 것을 허용하기 보다는 질의 컴파일 동안에 체크된다. 하지만 이것은
equal과는 대조적으로 등가인(equivalent) Hibernate Type들
사이에서 문제점들을 일으킬 수도 있음을 노트하라. 비록 데이터베이스가 구별짓지 않을 수 있거나 변환을 처리할 수 있을 지라도, 이것은
org.hibernate.type.DateType로서 정의된 프로퍼티와 org.hibernate.type.TimestampType으로
정의된 프로퍼티 사이에 불일치 쟁점들을 일으킨다.
id 프로퍼티의 경우, insert 문장은 당신에게 두 개의 옵션을 준다. 당신은 properties_list 내에 id 프로퍼티를 명시적으로
지정할 수 있거나(그것의 값이 대응하는 select 표현식으로부터 얻어진 경우) 또는 properties_list에서 그것을 생략할 수도 있다
(산출된 값이 사용되는 경우). 이 후자의 옵션은 데이터베이스 내에서 연산되는 id 연산자들을 사용할 때에만 이용 가능하다;
임의의 "메모리 내" 타입 연산자들과 함께 이 옵션을 사용하려고 시도하는 것은 파싱 동안에 예외상황을 일으킬 것이다. 이 논의의
목적 상, 데이터베이스 내 산출자(generator)들은 org.hibernate.id.SequenceGenerator
(그리고 그것의 서브클래스들) 그리고 임의의 org.hibernate.id.PostInsertIdentifierGenerator의
구현자들이라고 간주됨을 노트하라. 여기서 가장 주목할 만한 예외상황은 그것이 그것의 값들을 얻기 위한 select 가능한 방법을
노출시키지 않기 때문ㅇ에 사용될 수 없는 org.hibernate.id.TableHiLoGenerator이다.
version 또는 timestamp로서 매핑된 프로퍼티들의 경우에,
insert 문장은 당신에게 두 개의 옵션들을 준다. 당신은 properties_list 내에 그 프로퍼티를 지정할 수 있거나
(그 것의 값이 대응하는 select 표현식으로부터 얻어진 경우) 또는 properties_list에서 그것을 생략할 수 있다
(org.hibernate.type.VersionType에 의해 정의된 seed value
값이 사용되는 경우).
예제 HQL INSERT 문장 실행: