1장. 아키텍처

1.1. 정의들

EJB3는 J2EE 5.0 플랫폼의 부분이다. EJB3에서 영속성은 EJB3 컨테이너들에서 이용 가능할 뿐만 아니라 특정 컨테이너 외부에서 실행되는 J2SE 어플리케이션들에 대해서도 이용 가능하다. 다음 프로그래밍 인터페이스들과 산출물들은 두 환경들 모두에서 이용 가능하다.

EntityManagerFactory

엔티티 관리자 팩토리는 엔티티 관리자 인터페이스들을 제공하고, 모든 인스턴스들은 특정 구현 등에 의해 정의된 것과 동일한 디폴트 설정들을 사용하기 위해서, 동일한 데이터베이스에 연결하도록 구성된다. 당신은 여러 데이터 저장소들에 접근하기 위해서 여러 개의 엔티티 관리자 팩토리들을 준비할 수 있다. 이 인터페이스는 native Hibernate에서 SessionFactory와 유사하다.

EntityManager

EntityManager API는 하나의 특별한 작업 단위에서 하나의 데이터베이스에 접근하는데 사용된다. 그것은 영속 엔티티 인스턴스들을 생성시키고 제거시키는데, 그것들의 프라이머리 키 동일성(identity)로서 엔티티들을 찾는데, 그리고 모든 엔티티들에 대해 질의하는데 사용된다. 이 인터페이스는 Hibernate에서 Session과 유사하다.

영속 컨텍스트

영속 컨텍스트는 유일 엔티티 인스턴스가 존재하는 임의의 영속 엔티티 identity에 대한 엔티티 인스턴스들의 집합이다. 영속 컨텍스트 내에서, 엔티티 인스턴스들과 그것들의 생명주기는 특별한 엔티티 관리자에 의해 관리된다. 이 컨텍스트의 영역은 트랜잭션일 수 있거나, 하나의 확장된 작업 단위일 수 있다.

영속 단위

하나의 주어진 엔티티 관리자에 의해 관리될 수 있는 엔티티 타입들의 집합은 하나의 영속 단위에 의해 정의된다. 하나의 영속 단위는 어플리케이션에 의해 관계되거나 그룹지워지는 모든 클래스들의 집합을 정의하고, 그것은 단일 데이터 저장소로 그것들의 매핑 속에 함께 위치 지워져야 한다.

컨테이너에 의해 관리되는 엔티티 관리자

그 생명주기가 컨테이너에 의해 관리되는 엔티티 관리자.

어플리케이션에 의해 관리되는 엔티티 관리자

그 생명주기가 어플리케이션에 의해 관리되는 엔티티 관리자.

JTA 엔티티 관리자

하나의 JTA 트랜잭션에 수반된 엔티티 관리자

리소스-로컬 엔티티 관리자

(JTA 트랜잭션이 아닌) 하나의 리소스 트랜잭션을 사용하는 엔티티 관리자.

1.2. EJB 컨테이너 환경

1.2.1. 컨테이너에 의해 관리되는 엔티티 관리자

J2EE 환경에서 가장 공통적이고 광범위하게 사용되는 엔티티 관리자는 컨테이너에 의해 관리되는 엔티티 관리자이다. 이 모드에서, 컨테이넌느 엔티티 관리자를 열고 닫을 책임이 있다(이것은 어플리케이션에게는 투명하다). 그것은 또한 트랜잭션 경계들에 대해 책임을 진다. 컨테이너에 의해 관리되는 엔티티 관리자는 dependency injection을 통해 또는 JNDI 룩업을 통해 어플리케이션 내에서 획득되며, 컨테이너에 의해 관리되는 엔티티 관리자는 JTA를 필요로 한다.

1.2.2. 어플리케이션에 의해 관리되는 엔티티 관리자

어플리케이션에 의해 관리되는 엔티티 관리자는 어플리케이션 코드로 엔티티 관리자를 제어하는 것을 당신에게 허용해준다. 이 엔티티 관리자는 EntityManagerFactory API를 통해 검색된다. 하나의 어플리케이션에 의해 관리되는 엔티티 관리자는 현재의 JTA 트랜잭션(JTA 엔티티 관리자) 내에 수반될 수 있거나, 그 트랜잭션은 EntityTransaction API(리소스-로컬 엔티티 관리자)를 통해 제어될 수도 있다. 리소스-로컬 엔티티 관리자 트랜잭션은 하나의 직접적인 리소스 트랜잭션(예를 들어. Hibernate의 경우 하나의 JDBC 트랜잭션)으로 매핑된다. 엔티티 관리자 유형(JTA 또는 리소스-로컬)은 구성 시에, 즉 엔티티 관리자 팩토리를 설정할 때 정의된다.

1.2.3. 영속 컨텍스트 영역

하나의 엔티티 관리자는 영속 컨텍스트와 상호작용하는 API이다. 두 개의 공통된 방도들이 사용될 수 있다: 영속 컨텍스트를 트랜잭션 경계들에 바인딩 시키기, 또는 몇몇 트랜잭션들을 가로질러 영속 컨텍스트를 이용 가능하도록 유지하기.

가장 공통적인 경우는 영속 컨텍스트 영역을 현재의 트랜잭션 영역에 묶어두는(bind) 것이다. 이것은 JTA 트랜잭션들이 사용될 때 특히 편리하다: 영속 컨텍스트 영역은 JTA 트랜잭션 생명 주기와 연관된다. 하나의 엔티티 관리자가 호출될 때, 만일 현재의 JTA 트랜잭션과 연관된 영속 컨텍스트가 존재하지 않을 경우에, 영속 컨텍스트가 또한 열린다. 그 밖의 경우, 연관된 영속 컨텍스트가 사용된다. 영속 컨텍스트는 JTA 트랜잭션이 완료될 때 끝난다. 이것은 JTA 트랜잭션 동안에 어플리케이션이 동일한 영속 컨텍스트의 관리되는 엔티티들에 대해 작업하는 것이 가능할 것임을 의미한다. 달리 말해, 당신은 당신의 EJB 메소드 호출들을 가로질러 엔티티 관리자의 영속 컨텍스트를 전달하지 말아야 하지만, 당신이 하나의 엔티티 관리자를 필요로 할 때마다 간단하게 dependency injection 또는 JNDI 룩업을 사용하라. 리소스-로컬 관리자의 경우, 하나의 새로운 리소스 트랜잭션이 (EntityTransaction.begins()를 통해) 시작될 때 하나의 새로운 영속 컨텍스트가 시작되고 리소스 트랜잭션이 완료될 때 하나의 새로운 영속 컨텍스트가 끝난다. 만일 엔티티 관리자가 트랜잭션 영역의 외부에서 호출될 경우, 그 메소드 호출에만 서비스하기 위해 영속 컨텍스트가 생성되고 파괴되고, 데이터베이스로부터 로드된 모든 엔티티들은 그 메소드 호출의 끝에서 detach된다. 이것은 전통적인 JDBC에서 자동-커밋(auto-commit) 특징과 유사하다.

당신은 또한 하나의 확장된 영속 컨텍스트를 사용할 수 있다. 당신이 하나의 컨테이너에 의해 관리되는 엔티티 관리자를 사용할 경우, 이것은 상태있는 세션 빈즈와 결합될 수 있다: 영속 컨텍스트는 하나의 엔티티 관리자가 dependency injection 또는 JNDI 룩업으로부터 검색될 때 생성되고, 상태 있는 세션 빈(bean) 메소드 Remove의 완료 후에 컨테이너가 그것을 닫기 전까지 유지된다. 이것은 하나의 "긴" 작업 단위 패턴을 구현하는 하나의 완전한 메커니즘이다. 예를 들어, 만일 당신이 단일 작업 단위(예를 들면. 완전하게 완료되어야 하는 하나의 마법사 대화상자)로서 다중 사용자 상호작용 주기들을 다루어야 할 경우에, 당신은 대개 어플리케이션 사용자의 관점에서 이것을 하나의 작업 단위로 모형화 시키고, 하나의 확장된 영속 컨텍스트를 사용하여 그것을 구현한다. 이 패턴에 대한 추가 정보는 Hibernate 참조 매뉴얼 또는 Hibernate In Action 책을 참조하길 바란다. 어플리케이션에 의해 관리되는 엔티티 관리자의 경우에 영속 컨텍스트는 엔티티 관리자가 생성될 때 생성되고 엔티티 관리자가 닫히기 전까지 유지된다.

리소스-로컬 엔티티 관리자 또는 (어플리케이션에 의해 관리되는) EntityManagerFactory.createEntityManager()로 생성된 엔티티 관리자는 하나의 영속 컨텍스트와 하나의 일-대-일 관계를 갖는다. 다른 경우들에서는 영속 컨텍스트 전파 (persistence context propagation)가 일어난다.

1.2.4. 영속 컨텍스트 보급(propagation)

영속 컨텍스트 보급(propagation)은 컨테이너에 의해 관리되는 엔티티 관리자들에 대해 그리고 EntityManagerFactory.getEntityManager()를 통해 획득된 엔티티 관리자들에 대해 일어난다.

하나의 트랜잭션-영역의 컨테이너에 의해 관리되는 엔티티 관리자에서(J2EE 환경에서 공통적인 경우), JTA 트랜잭션 보급(propagation)은 영속 컨텍스트 리소스 보급(propagation)과 동일한 것이다. 달리 말해, 하나의 주어진 JTA 트랜잭션 내에서 검색된 모든 컨테이너-영역의 엔티티 관리자들은 모두 동일한 영속 컨텍스트를 공유한다. Hiberante 용어로, 이것은 모든 관리자들이 동일한 세션을 공유함을 의미한다.

하나의 JTA에 바인드된(묶인) 그리고 어플리케이션에 의해 관리되는 엔티티 관리자가 EntityManagerFactory.getEntityManager() 내에서 검색될 때, 반환된 엔티티 관리자는 JTA 트랜잭션에 묶인 영속 컨텍스트와 연관된다. 만일 영속 컨텍스트가 아직 연관되어 있지 않다면, 하나의 새로운 것이 생성되고 연관된다.

중요: 영속 컨텍스트는 다른 JTA 트랜잭션들 사이에서 또는 동일한 엔티티 관리자 팩토리로부터 생겨나지 않은 엔티티 관리자 사이에서 결코 공유되지 않는다. 확장된 영속 컨텍스트들을 사용할 때 컨텍스트 보급(propagation)에 대한 몇몇 주목할 만한 예외상황들이 존재한다:

  • 만일 하나의 트랜잭션 영역의 영속 컨텍스트를 가진 상태없는 세션 빈(bean), message-driven bean, 또는 상태있는 세션 빈(bean)이 동일한 JTA 트랜잭션 내에서 하나의 확장된 영속 컨텍스트를 가진 하나의 상태있는 세션 빈(bean)을 호출할 경우, IllegalStateException이 던져진다.

  • 만일 하나의 확장된 영속 컨텍스트를 가진 하나의 상태있는 세션 빈(bean)이 동일한 JTA 트랜잭션 내에서 하나의 트랜잭션-영역의 영속 컨텍스트를 가진 상태없는 세션 빈(bean)으로서 또는 하나의 상태있는 세션 빈으로서 호출될 경우, 그 영속 컨텍스가 보급된다.

  • 만일 하나의 확장된 영속 컨텍스트를 가진 하나의 상태있는 세션 빈(bean)이 다른 JTA 트랜잭션 컨텍스트 내에 있는 하나의 상태 있는 세션 빈(bean) 또는 하나의 상태 없는 세션 빈(bean)을 호출할 경우, 그 영속 컨텍스트는 보급되지 않는다.

  • 만일 하나의 확장된 영속 컨텍스트를 가진 하나의 상태있는 세션 빈(bean)이 하나의 확장된 영속 컨텍스트를 가진 또 다른 상태있는 세션 빈(bean)을 초기화 시킬 경우, 그 확장된 영속 컨텍스트는 두 번째 상태 있는 세션 빈(bean)에 의해 상속된다.만일 두 번째 상태 있는 세션 빈(bean)이 첫 번째 상태 있는 세션 빈이 아닌 다른 트랜잭션 컨텍스트에 대해 호출될 경우, IllegalStateException이 던져진다.

  • 만일 하나의 확장된 영속 컨텍스트를 가진 하나의 상태 있는 세션 빈(bean)이 동일한 트랜잭션 내에서 다른 확장된 영속 컨텍스트를 가진 하나의 상태 있는 세션 빈을 호출할 경우, IllegalStateException이 던져진다.

1.3. J2SE 환경들

J2SE 환경에서는 오직 어플리케이션에 의해 관리되는 엔티티 관리자들 만이 이용 가능하다. 당신은 EntityManagerFactory API를 사용하여 하나의 엔티티 관리자를 검색할 수 있다. 오직 리소스-로컬 엔티티 관리자들 만이 이용 가능하다. 달리 말해, JTA 트랜잭션들과 영속 컨텍스트 보급은 J2SE 환경에서는 지원되지 않는다(당신은 예를 들어 Hibernate 공동체에서 대중적인 쓰레드 로컬 세션 패턴을 사용하여, 당신 스스로 영속 컨텍스트를 보급해야 될 것이다).

하지만 당신은 두 개의 다른 엔티티 관리자 방도들 사이에서 여전히 선택할 수 있다. 첫 번째 것인 트랜잭션-영역의 엔티티 관리자는 EntityTransaction.begin()이 매번 호출될 때마다 한 개의 영속 컨텍스트를 생성시킬 것이다. 이 영속 컨텍스트는 트랜잭션 완료 시에 닫혀질 것이다. 이용 가능한 두 번째 방도는 확장된 컨텍스트이다. 그 경우에, 하나의 영속 컨텍스트는 (EntityManagerFactory.createEntityManager(EXTENDED)를 사용하여 ) 엔티티 관리자가 검색될 때 생성되고 엔티티 관리자가 닫혀질 때 닫혀진다. 많은 리소스-로컬 트랜잭션은 이 경우에 동일한 영속 컨텍스트를 공유한다.