SSISO Community

시소당

상태 유지 세션 빈에서의 확장 지속성 컨텍스트

EJB 3.0(Enterprise JavaBeans 3.0) 사양의 일부인 자바 지속성 아키텍처는 데이터 지속성을 사용하는 EJB 애플리케이션을 개발을 간소화했습니다. 그 대표적인 예가 데이터베이스에 액세스하고 트랜잭션 내부에서 엔터티를 생성, 제거하거나 업데이트하도록 EntityManager 인터페이스를 도입한 것입니다.

  엔터티는 데이터베이스에서 데이터를 나타내는 개체입니다. 엔터티를 생성한 애플리케이션이 종료하더라도 엔터티가 남아 있기  때문에 지속적이라고 말합니다. 엔터티의 지속성을 뒷받침하기 위해 엔터티 관리자가 지속성 컨텍스트와 상호 작용합니다. 자바  지속성 아키텍터에서는 이 컨텍스트를 다음과 같이 정의합니다.
지속성 엔터티 ID에 대해 고유한 엔터티 인스턴스가 존재하는, 관리 엔터티 인스턴스의 집합. 지속성 컨텍스트 내부에서 엔터티 인스턴스와 그 수명 주기는 엔터티 관리자에 의해 관리된다.

 또한 자바 지속성 아키텍처에 따르면, 컨테이너 관리 지속성 컨텍스트, 즉 수명 주기가 컨테이너에 의해 자동 관리되는 지속성 컨텍스트는 단일 트랜잭션 범위의 수명 또는 여러 트랜잭션을 포괄하는 확장된 수명을 갖도록 정의할 수 있습니다. 수명의 범위는 엔터티 관리자 생성 시 PersistenceContextType 클래스에 지정된 유형에 따라 결정됩니다.

 단일 트랜잭션을 범위로 하는 컨테이너 관리 지속성 컨텍스트의 경우, 연결된 트랜잭션이 커밋하거나 JTA(Java Transaction API)를 통해 롤백될 때 지속성 컨텍스트가 종료합니다. 그에 비해 확장된 수명을 갖는 컨테이너 관리 지속성 컨텍스트는 상태 유지 세션 빈이 생성될 때 시작하고, 상태 유지 세션 빈이 컨테이너에서 제거될 때만 종료합니다. 확장 지속성 컨텍스트는 상태 유지 세션 빈에 바인딩되었다고 말합니다. 상태 유지 세션 빈은 컨테이너에서 관리하는 확장 엔터티 관리자를 가질 수 있습니다.

  트랜잭션 범위 지속성 컨텍스트와 확장 지속성 컨텍스트의 중요한 차이점 중 하나는 트랜잭션 완료 후 엔터티의 상태입니다. 트랜잭션 범위 지속성 컨텍스트의 경우 엔터티는 분리됩니다. 즉 더 이상 관리되지 않습니다. 확장 지속성 컨텍스트의 경우 엔터티는  계속 관리됩니다. 다시 말해, persist와 같이 트랜잭션의 외부에서 수행되는 모든 작업이 대기열에 있다가 지속성 컨텍스트가 트랜잭션에 연결될 때 (그리고 커밋될 때) 커밋됩니다. 따라서 확장 지속성 컨텍스트는 여러 상호 작용을 포괄하는 사용자 대화를 모델링할 때 적합합니다. 사용자 대화 전체를 포괄하는 빈 관리 트랜잭션을 사용해도 똑같은 효과를 얻을 수 있습니다. UserTransaction.begin() 메소드를 사용하여 이 트랜잭션을 시작합니다. 그러나 이 대안은 확장 지속성 컨텍스트를 활용하는 것보다 더 복잡합니다.

 이 테크팁에서는 확장 지속성 컨텍스트와 함께 상태 유지 세션 빈과 엔터티 관리자를 사용하는 애플리케이션을 소개합니다. 이 애플리케이션에서는 여행 예약을 처리합니다. 사용자가 여행을 위해 항공편과 렌터카를 예약할 수 있습니다. 이 팁에는 샘플 패키지가 제공됩니다. 이 팁의 코드 예제는 해당 패키지에 포함된 샘플의 소스 코드에서 따온 것입니다.


여행 예약 애플리케이션

 이 팁의 애플리케이션에서는 사용자가 여행을 예약할 수 있는 간단한 웹 페이지를 제시합니다.

사용자 삽입 이미지

  여행 예약에서는 이용할 항공편 또는 차량을 예약합니다. 사용자는 출발지와 도착지를 지정하고 여행 날짜를 선택한 다음 항공기 또는 차량을 선택하여 예약합니다. 그런 다음 Book It 버튼을 선택하여 렌터카 또는 항공편 예약을 확인합니다. 사용자는 해당 여행에 여러 건의 예약을 수행할 수 있습니다. 그런 다음 Confirm 버튼을 클릭하여 자신이 선택한 내용을 확인합니다.

 애플리케이션의 소스 코드를 살펴보면, ControllerServlet 서블릿이 예약 웹 페이지를 제시합니다. 이 서블릿은 상태 유지 세션 빈 BookingControllerLocalBean을 사용하여 애플리케이션의 대화 상태를 유지합니다. 상태 유지 세션 빈에서는 엔터티 관리를 위해 컨테이너 관리 확장 지속성 컨텍스트를 사용합니다. 애플리케이션에서 confirmBooking()을 제외한 모든 메소드의 기본 트랜잭션 속성이 NOT_SUPPORTED입니다.

 다음 BookingControllerLocalBean 코드에서는 컨테이너 관리 확장 지속성 범위를 삽입합니다.

   @PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;


여행 예약 시작

 서블릿은 BookingControllerLocalBean에서 startBooking() 메소드를 호출하여 여행 예약 프로세스를 시작합니다. 서블릿에서의 메소드 호출은 다음과 같습니다.

   bookingController = (BookingControllerLocal) (new InitialContext()).lookup("java:comp/env/ejb/BookingController");
session.setAttribute("bc", bookingController);
tripId = bookingController.startBooking();

그리고 BookingControllerLocalBeanstartBooking() 메소드입니다.

   public Trip startBooking() {
this.trip = new Trip(); // Create a new Trip
em.persist(trip);

return trip(); //Return the Trip which is an Entity
}

다시 말하자면, 이 애플리케이션에서는 확장 지속성 컨텍스트를 사용하므로, 트랜잭션 없이 메소드가 호출되더라도 Trip 엔터티는 계속 관리됩니다.


항공편 및 차량 예약 처리

 사용자가 항공편이나 차량 예약을 요청하면 서블릿은 BookingControllerLocalBeandoBooking(Booking b) 메소드를 호출합니다. 이 메소드는 엔터티를 지속성으로 만들기 위해 em.persist 메소드를 호출합니다. 그러면 이 메소드는 다음과 같이 Trip 엔터티에 Booking 엔터티를 추가합니다.

 trip.getBookings().add(b);
b.setTrip(trip);

 트랜잭션 내부에서 doBooking() 메소드가 호출되지 않습니다. 그 때문에 엔터티는 데이터베이스로 플러시되지 않고, 계속 엔터티 관리자에 의해 관리됩니다. 따라서 doBooking() 메소드가 호출된 후에도 Booking 객체를 수정할 수 있습니다. 한편 이 애플리케이션이 트랜잭션 범위의 엔터티 관리자를 사용할 경우 엔터티 관리자가 다시 엔터티를 관리하게 하려면 다음 트랜잭션이 시작할 때 em.merge()를 호출해야 합니다. 하지만 애플리케이션에서는 확장 지속성 범위의 엔터티 관리자를 사용하므로, 이 엔터티는 트랜잭션 커밋 후에도 계속 관리됩니다.

다음은 doCarBooking() 메소드의 완성된 코드입니다.

   public void doBooking(Booking b) {
em.persist(b);

trip.getBookings().add(b);
b.setTrip(trip);
}


여행 예약 상태 표시

 서블릿은 BookingControllerLocalBeangetAllBooking() 메소드를 호출하여 여행의 모든 Booking 엔터티를 표시합니다. 이 메소드는 데이터베이스에서 데이터를 가져오지 않습니다. 그 대신 Trip 엔터티 내부의 Booking 엔터티 컬렉션을 가져옵니다.

다음은 getAllBooking() 메소드의 코드입니다. .

   public List<Booking>getAllBookings() {
return trip.getBookings();
}


여행 예약 완료

 사용자가 Confirm 버튼을 클릭하면 서블릿은 BookingControllerLocalBeanconfirmTrip() 메소드를 호출합니다. 이 메소드는 아무 작업도 수행하지 않습니다.

   @TransactionAttribute(TransactionAttributeType.REQUIRED)
public void confirmTrip() {
em.flush();
}

 그러나 메소드가 트랜잭션 내부에서 실행되므로 컨테이너는 확장된 지속성 관리자를 해당 트랜잭션과 자동으로 연결시킵니다. 메소드가 완료되면 컨테이너는 트랜잭션을 커밋하고 엔터티 관리자는 엔터티의 상태를 데이터베이스에 플러시합니다.


샘플 코드 실행하기

이 팁에는 샘플 패키지가 제공됩니다. 샘플을 설치하고 실행하려면 다음 단계를 수행합니다.

  1. 샘플 패키지를 다운로드하고 압축을 풉니다. techtip3.ear라는 이름의 엔터프라이즈 아카이브가 나타나야 합니다.
  2. GlassFish v2가 없을 경우, 먼저 다운로드하고 설치하십시오. 명령줄에 다음 명령을 입력하여 GlassFish v2를 시작합니다.
       <glassfish_install_dir>/bin/asadmin start-domain

    여기서 <glassfish_install_dir>는 GlassFish v2를 설치한 디렉토리입니다.

  3. GlassFish v2 패키지에 포함된 자바 DB 데이터베이스 서버를 시작합니다. 명령줄에 다음 명령을 입력합니다.
       <glassfish_install_dir>/bin/asadmin start-database

    여기서 <glassfish_install_dir>는 GlassFish v2를 설치한 디렉토리입니다.

  4. GlassFish v2에서 techtip3.ear를 배포합니다. 이 작업은 다양한 방법으로 수행할 수 있습니다. 그 중 하나는 명령줄에 다음 명령을 입력하는 것입니다.
       <glassfish_install_dir>/bin/asadmin deploy techtip3.ear
  5. 브라우저를 열고 URL: http://localhost:8080/techtip3-war/TripController로 이동합니다. 여행 예약 웹 페이지가 나타나야 합니다.


요약

 이 팁에서는 사용자와의 여러 상호 작용을 포괄하는 긴 대화를 처리하기 위해 확장 지속성 컨텍스트와 함께 컨테이너 관리 엔터티 관리자를 사용하는 예를 소개했습니다. 또한 이 예제에서는 중간 사용자 상호 작용을 하나의 트랜잭션 내에서 처리할 필요가 없도 이러한 유형의 엔터티 관리자가 트랜잭션 완료 시 어떻게 플러시되는지 살펴봤습니다.


저자 정보

Mahesh Kannan은 EJB 컨테이너 팀의 일원으로서 지난 7년간 자바 EE 개발에 참여해 왔습니다.

이 글의 영문 원본은
http://blogs.sun.com/enterprisetechtips/entry/extended_persistence_context_in_stateful
에서 보실 수 있습니다.

출처 : http://sdnkorea.com/blog/520

850 view

4.0 stars