제8장 Entity Bean

내용 목차

8.1. 개요
8.2. 주요 기능
8.2.1. 공통 기능
8.2.2. BMP & CMP 1.1
8.2.3. CMP 1.1/2.0
8.2.4. CMP 2.0
8.3. Entity EJB 설정
8.3.1. 공통 설정
8.3.2. CMP 1.1/2.0
8.3.3. CMP 2.0
8.3.4. DB Insert Delay 설정(CMP Only)
8.4. Entity EJB 튜닝
8.4.1. 공통
8.4.2. BMP & CMP 1.1
8.4.3. CMP 1.1/2.0
8.4.4. CMP 2.0
8.5. 완전한 CMP 2.0 Entity Bean 예제

Entity Bean은 EJB 3.0부터는 JPA로 대체되었다. 따라서 Bean을 새롭게 개발하는 경우는 JPA 사용을 권장한다. 그러나 기존 사용자를 위해 JEUS EJB 엔진은 Entity Bean를 지원한다.

본 장에서는 JEUS EJB 엔진에서 Entity Bean을 설정하고 튜닝하는 데 필요한 모든 정보에 대해 설명한다.

EJB 스펙에 따라 JEUS EJB 엔진은 다음과 같은 3가지 Entity Bean을 지원한다.

  • Bean Managed Persistence Entity Bean (BMP)

  • EJB 1.1 스펙에 따른 Container Managed Persistence Entity Bean(CMP 1.1)

  • EJB 2.0 스펙에 따른 Container Managed Persistence Entity Bean(CMP 2.0)

종류에 상관없이 JEUS의 Entity Bean들은 모두 “제4장 EJB의 공통 특성”에서 설명한 기능과 설정 컴포넌트들을 공유하므로 JEUS EJB 엔진에서 Entity Bean을 설정하고 사용하기 전에 관련 장의 내용에 대한 이해를 필요로 한다.

3개의 Bean 종류에 따라 3개의 설정이 존재한다.

  • 3가지 종류에 모두 적용되는 공통된 설정

  • CMP 1.1CMP 2.0에만 적용되고 BMP에는 적용되지 않는 설정

  • CMP 2.0에만 적용되는 설정

다음은 각 Entity Bean 종류별 설정 특성을 나타낸 표이다.

위의 표에서와 같이 항목 1부터 16까지는 모든 EJB에 공통으로 적용된다. 이 항목들은 “제4장 EJB의 공통 특성”에서 모두 설명하였다.

17번 항목은 Session Bean과 Entity Bean에 모두 해당되지만 사용법은 차이가 있어서 그 차이점을 중점적으로 설명한다. 항목 18부터 21까지는 Entity Bean에만 해당하는 항목들로 본 장에서 자세히 설명한다.

이 외에도 다음과 같은 JEUS Entity EJB에 연관된 주제에 대해서도 설명한다.

  • Default Primary Key 클래스

  • EJB QL 언어에 추가된 JEUS 특정 항목

  • JEUS Instant EJB QL API

참고

JEUS에서는 성능 튜닝이 EJB Entity Bean 설정의 가장 중요한 부분이다. 그러므로 본 장에서는 엔진 모드와 서브 모드와 같이 성능 관련 부분에 대해서 자세히 설명한다. 본 장 후반부의 “8.4. Entity EJB 튜닝”은 본 절에서 설명한 내용을 좀 더 간략하게 다시 정리한 것이다.

본 절에서는 Entity Bean의 공통 기능과 각 Bean의 주요 기능에 대해서 설명한다.

3가지 Entity Bean들은 종류에 상관없이 JEUS Entity Bean의 공통 기능을 갖는다.

다음은 EJB 엔진에서 Entity Bean Object가 어떻게 관리되는지 보여준다.


"object management"는 EJB 엔진의 내부적인 Bean Instance Pool과 Connection Pool을 의미한다. 이 Pool들은 각 Bean마다 설정되고 성능 향상과 시스템 자원의 효율적인 관리를 위해 사용된다. 기본적으로 Stateful Session Bean과 비슷하게 동작하므로 본 절에서는 차이점만 언급하고 자세한 내용은 “제7장 Session Bean”을 참고한다.

Entity Bean은 Connection Pool 외에 Entity Cache를 사용한다. Entity EJB가 passivate되려 할 때(passivation timeout이 지났을 때) 그 Bean Instance는 실제로는 바로 passivate되지 않는다(Stateful Session Bean의 경우에는 passivate된다). 대신에 이는 Entity Cache로 전달된다. 이 Cache에서는 모든 passivate된 Entity Bean들이 활성화 상태로 저장되어 있다(즉, 식별이 가능하고, 유효한 상태를 유지한다). 다른 Pool들과 마찬가지로 이 Entity Cache도 런타임 메모리에 유지되고, 따라서 활성화 상태와 passivate 사이의 존재하지 않는 상태에서 Runtime Cache로 작동된다.

Entity Bean이 실제적으로 passivate되는 때는 다음과 같다.

Entity Cache가 사이즈를 줄여야 할 때 passivate가 된다. 새로운 Entity Bean이 Cache로 들어오려 할 때 그 Cache에 이미 passivate된 Bean들이 많이 있을 경우 Cache 내의 Bean들이 강제로 밀려 나간다. 이렇게 강제로 밀려 나간 Entity Bean은 passivate되고 그 상태는 DB에 쓰여지며 그 Instance는 Bean Pool로 반환되거나 Bean Pool이 가득 차 있는 상태라면 버려진다. Cache에 막 들어오려는 Entity Bean은 Cache에 진입하여 결과적으로 강제로 밀려난 Bean Instance의 자리를 차지하게 된다.

Cache 크기는 <persistence-optimize>/<entity-cache-size>로 조절 가능하다. 반드시 설정한 크기만큼 찼을 때 Cache 크기를 줄이는 것은 아나라 힌트로 사용된다. 또한 강제로 밀려나가는 Bean Instance를 선택하는 방법 또한 Cache에 오래 머문 순이 아니다.

이러한 Cache를 사용하면 시간이 많이 소모되는 passivation을 효과적으로 관리할 수 있다는 장점이 있다. Cache를 사용함으로써 passivate된 Entity Bean을 다시 활성화시킬 때 DB에 접근할 필요가 없어지고 Cache에 있는 Instance(만약에 존재하면)를 사용함으로써 해결할 수 있다.

Object Pool의 표준 passivation timeout 값이 시간적인 제약을 관장하는 passivation 값이라면 Entity Cache는 메모리의 제약을 관장하는 passivation 설정값이라고 할 수 있다. 이것이 Entity Cache를 사용하는 주요 동기이다.

주의

Entity Cache 설정은 실제로 "object management"의 설정이 아니라 일반적인 Entity Bean persistence 최적화 설정이다. 이에 대한 자세한 내용은 “8.3. Entity EJB 설정”에서 설명한다.

Entity Bean에 대해 어느 시기에 ejbLoad() 메소드를 호출할 것인지 결정하는 것은 EJB 엔진(컨테이너)이다. 이 메소드는 DB의 상태 정보와 Bean Instance의 런타임 상태 정보를 동기화하기 위해 BMP와 CMP에서 사용한다. 본질적으로 ejbLoad() 메소드는 DB에서 하나의 레코드를 읽고 그 결과를 Bean의 내부 특성 값들에 설정하기 위해 사용된다.

ejbLoad() 메소드는 Entity Bean의 생명주기 동안 적어도 한 번은 호출된다. 어떤 경우에는 Bean Instance의 호출할 때마다 바로 전에 ejbLoad() 메소드를 호출할 필요가 생기기도 한다.

DB에서 Bean의 상태 정보를 읽어야 하는 시나리오는 기본적으로 크게 2가지가 있다.

  • Entity Bean이 여러 개의 EJB 엔진에 걸쳐 클러스터되어 있을 때 그 중 하나의 Bean이 DB의 한 레코드를 변경시킬 수 있다. 즉, 클러스터링된 Entity Bean들이 서로 통신할 수 없기 때문에 특정 Entity Bean Instance의 상태 정보가 가장 최신의 것이라는 것을 보장할 수 없다.

  • 어떤 외부 요소(작업자 또는 시스템)가 EJB와 연동되어 있는 DB를 변경할 경우가 있다.

    이 시나리오에서 EJB 엔진의 특정 EJB Instance는 DB의 내용을 제대로 반영하지 못한 상태가 된다.

다음 그림은 Entity Bean이 클러스터링되어 있을 때나 외부에서 Bean의 DB 행을 수정했을 때 ejbLoad()가 주기적으로 호출되는 2개의 시나리오이다.


위의 두 시나리오의 상황을 피할 수만 있다면(클러스터링을 사용하지 않고, 어떤 외부 요소도 EJB의 DB 데이터를 변경하지 않는다고 보장한다면) Entity Bean의 ejbLoad() 동작을 최적화할 수 있다.

EXCLUSIVE_ACCESS 엔진 모드를 Bean에 적용하면 최적화가 가능하다. 이 모드를 사용하면, ejbLoad()는 Bean이 Instance화될 때 단 한 번만 호출된다. 이렇게 함으로써 DB의 접근량을 약 50%정도 줄일 수 있다.

다음 그림은 EXCLUSIVE_ACCESS 모드가 사용될 때의 시나리오를 보여주고 있다. EXCLUSIVE_ACCESS는 단지 하나의 Bean이 DB 행을 사용하고 대부분의 ejbLoad()는 최적화된다.


Bean을 클러스터링해야 하거나 외부 요소가 EJB 데이터를 변경시켜야 한다면 SINGLE_OBJECT 또는 MULTIPLE_OBJECT 엔진 모드를 사용해야 한다. 두 모드 중 하나가 사용되면, EJB 엔진은 EJB 클라이언트의 요청이 도착할 때마다 ejbLoad() 메소드를 호출한다. 이렇게 하면 각 Entity Bean의 성능이 저하되지만 모든 상태 정보가 DB에 의해 관리되기 때문에 다른 엔진과 Bean들에게 부하를 분산시킬 수 있다.

다음은 SINGLE_OBJECT와 MULTIPLE_OBJECT 모드의 차이점에 대한 설명이다.

다음은 각 엔진 모드를 선택할 때의 장점과 단점을 비교한 표이다.

3가지 엔진 모드 중 적합한 모드를 선택하기 위한 기준은 다음과 같다.

  • 많은 양의 요청이 Entity Bean에 요청되고, 많은 수의 EJB 엔진들이 설정되어 있다면 SINGLE_OBJECT 모드를 선택하고 엔진들에 Bean을 클러스터링으로 구성한다.

  • 많은 양의 요청이 Entity Bean에 요청되지만, 한정된 EJB 엔진이 설정되어 있으면 MULTIPLE_OBJECT 모드를 선택하고 엔진들에 Bean을 클러스터링으로 구성한다.

  • MULTIPLE_OBJECT와 SINGLE_OBJECT를 선택할 때 고려해야 할 중요한 사항 중의 하나는 한 트랜잭션을 수행하기 위해 필요한 총 시간이다. 수행 시간이 많이 소요되는 트랜잭션이라면 당연히 MULTIPLE_OBJECT를 선택할 것을 권장한다.

  • 많지 않은 동시 요청이 Entity Bean에 들어온다면 EXCLUSIVE_ACCESS 모드를 선택하고 하나의 EJB 엔진에 Bean을 deploy한다.

EJB 클러스터링에 대한 자세한 정보는 “제6장 EJB 클러스터링”의 설명을 참고한다.

본 절에서는 ejbStore() 호출을 최적화하는 방법에 대해 설명한다.

참고

본 절에서 설명하는 ejbStore() 호출의 최적화 방법은 BMP와 CMP 1.1 Bean들에만 적용되고, CMP 2.0은 다른 방법으로 접근해야 한다.

본 절에서는 CMP 1.1/2.0의 주요 기능에 대해서 설명한다.

“8.2.1.2. 엔진 모드 Selection을 통한 ejbLoad() Persistence 최적화”“8.2.2.1. Non-modifying 메소드에 의한 ejbStore() Persistence 최적화”에서 ejbLoad()와 ejbStore() 메소드의 호출 시점에 대해서 설명하였다. BMP와 CMP는 ejbLoad()와 ejbStore() 메소드를 사용하기 때문에 BMP와 CMP Entity Bean에만 적용되었다.

본 절에서는 성능향상을 위해 ejbLoad()와 ejbFind() 메소드를 최적화하는 방법에 대해서 설명한다. ejbLoad(), ejbFind()의 구현 방법은 EJB 엔진에 영향을 받기 때문에 CMP Bean(1.1과 2.0 버전)에 국한해서 설명한다. BMP에서 해당 메소드의 구현과 작동 방식은 개발자에 의해 결정된다.

EJB 엔진이 CMP ejbLoad(), ejbFind()를 호출하면 다음과 같은 엔진의 하위 모드를 선택하여 작동 방식을 최적화할 수 있다. 3가지 모드에 대한 자세한 기술적 설명은 하지 않는다.

모드설명
ReadLockingejbLoad()를 호출할 때 EJB 엔진이 DB의 Shared Lock을 가질 수 있게 한다. 이 종류의 Lock은 다른 Bean들이 같은 레코드를 읽을 수 있지만 쓰는 것은 금지한다.
WriteLockingejbLoad()를 호출할 때 EJB 엔진이 DB의 Exclusive Lock을 가질 수 있게 한다. 다른 Bean들이 DB에 읽고 쓰는 것을 모두 금지한다.
WriteLockingFindejbLoad()와 ejbFind()를 호출할 때 EJB 엔진이 DB의 Exclusive Lock을 가질 수 있게 한다. 다른 Bean들이 DB에 읽고 쓰는 것을 모두 금지한다.

위의 3가지 모드가 사용되어야 하는 상황은 다음과 같다.

  • CMP Bean이 쓰기 작업보다는 읽기 작업을 더 빈번히 수행하면 항상 ReadLocking 모드를 선택한다.

  • CMP Bean이 읽기 보다는 쓰기 작업을 더 많이 수행하면 WriteLocking 모드나 WriteLockingFind 모드를 선택한다.

CMP에서는 엔진 모드와 앞 절에서 설명한 Non-modifying 메소드, 그리고 본 절에서 설명한 엔진 내 하위 모드가 규칙에 맞게 조합되어 설정되어야 한다. 이 모든 파라미터들의 설정 요약은 “8.4. Entity EJB 튜닝”의 설명을 참고한다.

또한 CMP Bean에서는 java.sql.ResultSet의 Fetch Size, EJB 엔진이 기동(Booting)할 때 Caching되어야 하는지의 여부와 EJB Bean Instance가 미리 Instance되어야 할지 등을 결정하는 <init caching> 설정을 할 수 있다.

경우에 따라 개발자들은 Primary Key 생성 없이 EJB Instance를 생성해야 할 때가 있다. 이 경우 JEUS EJB 엔진이 새로운 EJB Instance에게 할당할 고유의 Primary Key를 생성하도록 설정할 수 있다.

JEUS EJB 엔진은 이 기능을 DB와 연동하여 제공한다. 이러한 자동 Primary Key 생성 기능에 대해 JEUS EJB 엔진은 DB와 연동하여 제공하고, CMP 1.1과 CMP 2.0에 적용된다. 이 기능을 사용하면 Primary Key에 신경쓰지 않고 손쉽게 EJB를 개발할 수 있다.

다음은 자동 Primary Key 생성 기능의 사용 방법과 적용 과정에 대한 설명이다.

  1. 개발자들은 습관적으로 CMP1.1/CMP2.0을 파라미터 없이 create()를 호출한다. 이것은 create() 메소드가 EJB의 Primary Key가 되는 파라미터를 갖지 않는다는 의미이다.

    InitialContext ctx = new InitialContext();
    BookHome bHome = (BJookHome) ctx.lookup("bookApp");
    Book b = bHome.create(“JEUS EJB Guide”, ”Park Sungho”);
    // Start using “b”.
    . . .

    위의 예제에서 EJB Home인 BookHome을 찾고 EJB Home에서 파라미터가 2개인 create()를 호출한다("JEUS EJB Guide"와 "Park Sungho"). 이 파라미터는 새로운 책의 제목과 저자 이름을 뜻한다. 저자는 다르나 동일한 제목의 책이 있을 수 있기 때문에 이 파라미터들을 Primary Key로 이용하는 것은 적합하지 않다.

    이 기능을 지원하기 위해 EJB 엔진은("A") 반드시 고유의 Primary Key를 생성해서 새 책에 할당해야 한다. 그리고 여러 엔진들("B", "C")이 클러스터링된 상태에서도 같은 일이 동시에 발생할 수 있다는 것을 고려해야 한다.

    광범위한 클러스터링 중에도 각 엔진들은 고유한 Primary Key를 얻을 수 있어야 하기 때문에 하나의 중앙 저장장치를 필요로 한다. 이 저장장치는 하나의 컬럼과 하나의 데이터로 이루어진 DB로 구현된다.

    이 하나의 값은 EJB 엔진과 연동하면서 계속 증가하는 Primary Key Counter(또는 Primary Key Generator)이다. 이 방법으로 DB는 항상 클러스터링된 EJB 엔진이 읽을 수 있는 새롭고 고유한 Primary Key를 유지할 수 있다.

  2. Primary Key가 없는 create()가 호출되면, EJB 엔진 "A"는 중앙 저장장치(Primary Key DB)로 접근한다. 이 저장장치로부터 정수로 된 Primary Key를 받아오고 Book Instance에 할당한다.

  3. EJB 엔진 "A"는 저장장치에 있는 미리 결정된 값으로 Primary Key를 증가시킨다. 미리 결정된 값(Key Cache Size)은 기본적으로 "1"이다. 그러나 1 이상을 사용할 것을 권장한다("20").

    만약 Key Cache Size가 "20"이라면, EJB 엔진 "A"는 "19" (20-1)를 할당한다. 다음에 Primary Key를 읽는 다른 EJB 엔진("B"와 "C")은 가장 최근에 Primary Key를 읽어간 것보다 20이 큰 값을 읽게 된다.

    이것은 EJB 엔진 "A"는 19개까지는 외부의 Primary Key 저장장치에 접근 없이 EJB Instance를 생성할 수 있다는 것을 의미한다. 따라서 성능 향상에 큰 기여를 한다. 엔진 "A"는 할당받은 Primary Key의 Counter를 유지함으로써 이 값을 모두 소비했을 때에만 외부에서 새로운 Primary Key를 읽어 온다. 내부적인 Counter는 물론 Primary Key를 생성하는 데 사용된다.

다음은 자동 Primary Key 생성의 특징에 대한 설명이다.

다음은 각 DB에 설정하는 방법에 대해 설명한다.

Oracle DB에서 Primary Key 생성 설정

Oracle DB에서 자동 Primary Key 생성은 Oracle에서 사용하는 Sequence 객체를 이용한다. 자동 Primary Key 생성 기능을 설정하기 전에 Sequence 객체가 생성되어 있어야 한다. Sequence 설정에 관련한 내용은 Oracle 문서를 참고한다.

다음은 Oracle DB에서 Primary Key를 생성하는 jeus-ejb-dd.xml의 예이다.


위 예제에서 Primary Key 생성 타입을 "Oracle"로 설정했으며, <generator-name>을 “my_generator”로 하고 <key-cache-size>를 "20"으로 설정했다.

MS SQL 서버에서 자동 Primary Key 생성 설정

MS SQL 서버에서 자동 Primary Key 생성은 간단하다. MS SQL 서버는 자동으로 고유의 IDENTITY 컬럼에 Primary Key를 유지한다.

다음은 MS SQL 서버에서 자동 Primary Key 생성을 설정한 jeus-ejb-dd.xml의 예이다.


<generator-type>에 "MSSQL"을 입력한다. MS SQL 서버는 <data-source-name>에서 선택된다.

Other DB의 자동 Primary Key 생성 설정

만약 Oracle과 MS SQL 서버 외에 다른 DB를 이용해서 자동 Primary Key를 생성한다면, 다음의 절차를 반드시 지켜야 한다.

  1. 다음과 같이 DB에 테이블을 하나 생성한다. 테이블은 하나의 컬럼과 하나의 열을 갖고 있어야 하고, 값은 '0'으로 설정되어야 한다.

    다음은 Primary Key 값을 관리할 테이블이다.

    Primary Key generator table PrimKeyTable
     PrimKeyGeneratorColumn (Primary Key 값이 저장되는 컬럼)
    Row 10 (Primary Key 값의 초기값)

    위의 테이블은 다음의 SQL로 생성된다.

    CREATE table PrimKeyTable (PrimKeyGeneratorColumn int);
    INSERT into PrimKeyTable VALUES (0);
  2. 테이블을 생성하고 jeus-ejb-dd.xml을 다음과 같이 수정한다.


    위 예제에서 타입은 'USER_KEY_table'이고, 테이블 이름이 'PrimKeyTable'이다. 컬럼 이름은 'PrimKeyGeneratorColumn'이고 Key Cache 크기는 '20'으로 설정했다.

    DB를 사용하기 위해서 설정하는 <data-source-name> 태그의 값은 JEUSMain.xml의 DB Connection Pool의 <export-name>과 일치해야 한다.

본 절에서는 CMP 2.0의 주요 기능에 대해서 설명한다.

본 절에서는 다음과 같은 JEUS Entity EJB의 설정 방법을 설명한다.

  • 모든 Entity Bean에 적용 가능한 설정

    • 기본적이고 공통적인 설정들

    • Object Pool

    • Entity Cache 설정을 포함한 Persistence 최적화

  • CMP에만 적용 가능한 설정

    • CM persistence optimization 최적화

    • 스키마 정보 설정

  • CMP 2.0에만 적용 가능한 설정

    • Relationships 매핑 설정

    • Instant EJB QL 설정

모든 특성들은 JEUS EJB모듈 DD(jeus-ejb-dd.xml)의 <beanlist> 태그 아래의 <jeus-bean>에 설정된다.

다음은 모든 Entity Bean에 적용 가능한 기본 설정에 대한 설명이다.

다음은 Object Management 관련 설정이 된 XML 예제로 <jeus-bean><object-management> 태그 내에서 구성된다.


다음은 설정 태그에 대한 설명이다.

  • <bean-pool>

    • EJB Bean Instance Pool의 작동 방식을 결정한다.

    • 하위 태그들은 다음과 같다.

      태그설명
      <pool-min>Pool을 초기화할 때 생성해두는 초기 Bean Instance 개수와 Pool에 유지하려는 최소 Bean Instance의 개수(resizing 작업할 때 Pool에 남기는 Instance의 개수)이다. (기본값: 0)
      <pool-max>

      Instance의 사용이 끝난 후 Pool에 저장 여부를 결정하는 Pool이 가질 수 있는 최대 Bean Instance 개수이다. Session Bean은 <pool-max> 설정값까지만 생성할 수 있으므로 그 이상의 요청이 한 번에 오면 EJB Exception이 발생한다.

      반면, Entity Bean은 Bean Instance 생성에는 제한이 없고 사용 후에 Pool에 보관할 개수를 제한한다. (기본값: 100)

      <resizing-period>Pool의 크기를 재조정하는 시간으로 "resizing"은 사용되지 않는 Bean Instance들이 Pool의 최솟값까지 제거됨을 의미한다. (기본값: 5분, 단위: ms)

  • <connect-pool>

    • 클라이언트와 Bean Instance를 연결하는 connection을 몇 개까지 유지할 것인지를 설정한다. 해당 옵션은 Session Bean에서는 사용하지 않는다.

    • 하위 태그들은 다음과 같다.

      태그설명
      <pool-min>Pool에 유지하려는 최소 connection의 개수로 resizing 작업할 때 Pool에 남기는 Instance의 개수이다. (기본값: 0)
      <pool-max>connection 사용이 끝난 후 Pool에 저장 여부를 결정하는 Pool이 가질 수 있는 최대 connection 개수이다. (기본값: 100)
      <resizing-period>Pool의 크기를 재조정하는 시간으로 "resizing"은 사용되지 않는 connection들이 Pool의 최솟값까지 제거됨을 의미한다. (기본값: 5분, 단위: ms)

  • <capacity>

    • 생성될 것으로 예상되는 Bean Instance의 최대 개수를 의미하며, Entity Bean에만 사용된다. 이 값은 EJB와 연계될 내부 클라이언트 세션 데이터의 효율적인 구성을 위해 사용된다. (기본값: 10000)

  • <passivation-timeout>

    • 지정된 시간 동안 클라이언트의 요청을 받지 않은 Bean을 passivate할 때 사용된다.

      여기에 설정된 시간을 초과하는 동안 클라이언트의 요청이 없는 Bean Instance가 passivate 대상이 된다. passivate 대상인 Bean Instance가 메모리에 남아 있는 개수를 <persistence-optimize>/<entity-cache-size>로 조절할 수 있다.

    • Stateful Session Bean의 경우는 Entity Cache라는 것이 없어 설정한 시간 동안 요청이 없으면 passivate되지만 Entity Bean의 경우는 Entity Cache에 머물러 있다가 passivate된다. 어떤 Bean이 passivate되는지 검사하는 주기는 EJB 엔진에 설정한 resolution을 따른다. (기본값: 5분)

      passivate가 실행되면 메모리에서 해당하는 Bean Instance가 제거된다.

    • 이 설정은 다음과 같이 여러 곳에서 설정 가능하고 우선순위는 다음과 같다.

      1. 특정 Session Bean에만 적용 : jeus-ejb-dd.xml의 <passivation-timeout>

      2. 모든 Entity Bean에 적용 : 시스템 프로퍼티 jeus.ejb.entity.passivate

      3. 모든 EJB Bean에(Entity Bean과 Session Bean 모두) 적용 : 시스템 프로퍼티 jeus.ejb.all.passivate

      위의 모든 설정이 없으면 기본값으로 설정된다. (기본값: 300000(5분), 단위: ms)

  • <disconnect-timeout>

    • 지정된 시간 동안 클라이언트의 요청을 받지 못하면 클라이언트와 Bean Instance 사이를 연결하던 connection을 끊을 때 사용된다. 그렇게 되면 connection은 각각의 클라이언트와 인스턴스가 맺고 있던 연결을 끊고 Connection Pool로 반환된다.

      따라서 클라이언트는 이 connection으로 더 이상 요청을 할 수 없고, 사용 중이던 Bean Instance는 삭제되거나 Bean Pool을 사용 중이면 Bean Pool로 반환된다.

    • 이 설정은 다음과 같이 여러 곳에서 설정 가능하고 우선순위는 다음과 같다.

      1. 특정 Session Bean에만 적용 : jeus-ejb-dd.xml의 <disconnect-timeout>

      2. 모든 Entity Bean에 적용 : 시스템 프로퍼티 jeus.ejb.stateful.disconnect

      3. 모든 EJB Bean에(Entity Bean과 Session Bean 모두) 적용 : 시스템 프로퍼티 jeus.ejb.all.disconnect

      위의 모든 설정이 없으면 시스템 프로퍼티 jeus.ejb.all.disconnect의 기본값인 3600000(1시간)으로 설정된다. (단위: ms)

참고

<passivation-timeout>과 <disconnect-timeout>에 사용되는 시간은 Bean Instance에 액세스했던 마지막 시점부터 측정된다. 그러므로 <disconnect-timeout>을 <passivation- timeout>보다 길게 설정해야 한다. 또한 <passivation-timeout>은 EJB 엔진에 설정되는 resolution보다는 커야 한다.

타임아웃 값을 길게 설정하면 오랜 시간(대략 십여 분 이상 또는 타임아웃이 중지된 경우) 동안 메모리 안에 많은 Instance가 활성화된 상태로 머물러 있다. 그러므로 시스템 자원이 낭비된다. 타임아웃 값이 수 초정도로 너무 짧으면 passivation, activation 등의 작업이 자주 발생되므로 성능을 저하시킬 수 있고 disconnect 작업으로 인해 세션의 유실 가능성이 있다.

Persistence 메소드 호출의 최적화는 jeus-ejb-dd.xml의 각 Bean DD에 설정되어 있다.

다음은 ejbLoad(), ejbStore() 메소드의 Persistence 최적화 설정된 XML 예제로 <jeus-bean><persistence-optimize> 태그 내에서 구성된다.


다음은 설정 태그에 대한 설명이다.

태그설명
<engine-type>

다음 중에 하나로 설정되어야 한다. 각 설정에 대한 차이는 “8.2. 주요 기능”의 설명을 참고한다.

  • EXCLUSIVE_ACCESS (기본값)

  • SINGLE_OBJECT

  • MULTIPLE_OBJECT

<non-modifying-method>ejbStore()가 호출되어야 하는지에 대한 힌트를 EJB 엔진에 제공한다. 이 태그는 CMP 2.0 Bean에서는 적용되지 않는다.
<entity-cache-size>passivate되어야 할 Entity Bean Instance들을 위한 내부 Cache의 크기를 결정한다. Cache에 담을 수 있는 Entity Bean Instance의 최대 크기 만큼이 주어진다. 크기가 클수록 좋은 성능을 가질 수 있지만 시스템 리소스(주 메모리)는 그 만큼 더 많이 사용된다. (기본값: 2000)
<update-delay-till-tx>

Boolean 값을 가지며 EJB 데이터의 update, insert가 트랜잭션이 commit될 때까지 지연될지를 나타낸다.

이 값이 false이면 모든 update, insert 작업은 즉각 실행되므로, 동일한 트랜잭션 내에서는 commit()이 호출되기 전에도 변경 사항을 확인할 수가 있지만 성능에 악영향을 미친다. (기본값: true)

<include-update>

<schema-info><jeus-query><include-updates>의 기본값을 지정한다.

이 값이 true일 경우 finder 메소드가 호출되는 동안에 생성된 update가 commit되므로, finder 메소드가 실행될 동안 업데이트된 정보를 조회할 수 있다.

(기본값: false)

다음은 CMP 1.1/2.0의 설정에 대한 설명이다.

CMP 1.1/2.0에서는 DB 테이블과 컬럼에 대응하는 EJB Instance 필드와의 매핑을 포함하고 있는 DB 스키마 정보를 설정해야 한다.

다음은 DB 스키마 정보를 설정한 XML 예제로 <jeus-bean><schema-info> 태그 내에 구성된다.


본 절에서는 CMP 2.0 설정에 대해서 설명한다.

2개의 Bean 사이에 Relationship Mapping을 설정하는 방법은 다음과 같이 경우에 따라 달라진다.

One-to-one/One-to-many Relationship Mapping

2개의 Bean 간에 One-to-one/One-to-many Relationship을 설정할 때 <ejb-relation-map> 태그 내에 설정해야 한다.

다음은 'employee-manager'라는 관계를 가지는 2개의 Bean 간에 Many-to-one(= One-to-many) 관계를 설정한 예로 <ejb-relation-map> 태그에 설정한다.


다음은 설정 태그에 대한 설명이다.

  • <relation-name>

    ejb-jar.xml 파일에 정의되어 있다.

  • <jeus-relationship-role>

    2개의 JEUS Relationship의 역할을 Relationship의 각 방향별로 하나씩 설정한다. 각 Relationship의 역할에 필요한 정보는 다음과 같다.

    • <relationship-role-name>

      ejb-jar.xml의 <ejb-relationship-role-name> 태그에 정의되어 있다.

    • <column-map>

      2개의 하위 태그인 <foreign-key-column>과 <target-primary-key-column>을 가진다.

      태그설명
      <foreign-key-column>Relationship에서 Foreign Key의 역할을 하는 컬럼의 이름이다.
      <target-primary-key-column>

      Foreign Key 컬럼이 매핑되어야 할 테이블의 Primary Key 필드이다.

      Key가 여러 개의 컬럼으로 구성되어 있으면 여러 개의 컬럼 대 컬럼 매핑을 지정할 수 있다.

위의 XML 예제에서는 employee 테이블의 manager-id라는 Foreign Key 컬럼이 employee-to-manager의 Many-to-one 관계를 맺기 위해 manager 테이블의 Primary Key 필드와 매핑되어 있다.

One-to-one Mapping도 이와 비슷한 방법으로 설정된다. 단, One-to-one 관계에서는 Primary Key 컬럼과 Foreign Key 컬럼이 테이블 어디에 존재해도 상관없으며, One-to-many에서는 반드시 “many” 측의 테이블이 Foreign Key 컬럼을 가지고 있다는 것을 유념한다.

Many-to-many Relationship Mapping

2개의 Bean 간에 Many-to-many 관계를 맺기 위해서는 One-to-one의 관계에서 설정된 정보 외에 추가로 <table-name>과 <jeus-relationship-role>의 정보가 반드시 설정되어야 한다.

다음은 Many-to-many 관계 설정을 나타내는 'student-course'의 예이다.


다음은 설정 태그에 대한 설명이다.

태그설명
<table-name>Many-to-many 관계의 Join 테이블 이름을 지정한다.
<jeus-relationship-role>2개의 <jeus-relationship-role>에서 각 Join 테이블 2개의 Foreign Key 컬럼을 Bean이 사용하는 테이블의 Primary Key 컬럼에 매핑한다.

위의 예에서 두 JEUS Relationship Role이 어떻게 사용되고 있는지 확인할 수 있다. 각 role은 Join 테이블의 두 컬럼 중 한 개와 실제 Bean이 사용하는 테이블의 Primary Key 컬럼이 매핑하도록 선언하고 있다.

본 절에서는 JEUS CMP에 관련된 EJB QL Extension에 대해 설명한다.

JEUS CMP에 관련된 EJB QL Extension은 다음과 같다.

  • JEUS EJB QL Extension 키워드

  • JEUS EJB QL Extension Subquery

  • JEUS EJB QL Extension ResultSet

  • JEUS EJB QL Extension Dynamic Query

  • JEUS EJB QL Extension GROUP BY 키워드

CMP 2.0 Bean의 findByXXX() 메소드와 ejbSelectXXX() 메소드에서는 그 home interface와 ejb-jar.xml의 EJB QL 문장이 연계되어 있어야 한다. JEUS는 표준 EJB QL 언어에 몇 가지 사항들을 추가한다. 이 추가 사항들은 ejb-jar.xml 파일이나 EJB QL에서 사용된다. 이 기능이 사용된 ejb-jar.xml의 예는 “8.5. 완전한 CMP 2.0 Entity Bean 예제”를 참고한다.

주의

본 안내서에서 제공된 EJB QL Extension들은 표준 EJB 2.1 QL에서 지원하지 않는 항목들로서 이것을 이용하여 작성된 EJB 애플리케이션은 Jakarta EE 표준에 준하지 않으므로 이식성이 떨어진다. 이 의미는 여기서 제공된 확장 기능을 사용하여 생성한 EJB 컴포넌트는 다른 Jakarta EE 서버에 deploy될 수 없다는 것이다. JEUS의 EJB QL Extension은 대부분 표준 SQL처럼 작동한다. 그러므로 더 상세한 정보는 SQL을 참고한다.

JEUS EJB QL Extension 키워드 추가사항

JEUS에서는 다음과 같은 비표준 키워드들이 EJB QL 문장에 사용될 수 있다.

JEUS EJB QL Extension Subquery

JEUS의 EJB QL Subquery는 EJB QL 질의의 하나로 WHERE 절에 포함된 또 다른 질의절을 의미한다. 이것은 SQL 질의와 Subquery의 관계와 비슷하다.

다음의 예에서는 중첩된 EJB QL 질의의 한 예로서 평균 이상의 월급을 받는 고용인들을 질의한다.

SELECT OBJECT(e)
FROM EmployeeBean AS e
WHERE e.salary >
    (SELECT AVG(e2.salary)
     FROM EmployeeBean AS e2)

  • 리턴 타입

    JEUS EJB QL 질의에 대해 다음과 같은 리턴 타입들이 올 수 있다.

    • Single value 또는 <cmp-field>에 대응하는 Collection(위의 예에서 e.salary와 같은 값들)

    • 집합 함수를 통해서 생성된 한 개의 리턴값(예: MAX(e.salary))

    • 간단한 Primary Key(Compound Primary Key가 아닌)를 포함한 cmp-Bean(예: SELECT OBJECT(emp))

  • 비교 연산자

    JEUS EJB QL은 Subquery를 비교 연산자의 피연산자로 사용할 수 있다.

    JEUS EJB QL은 비교 연산자는 다음과 같다.

    • [NOT] IN, [NOT] EXISTS, [NOT] UNIQUE

    • <, >, <=, >=, =, <>

    • 위 연산자와 ANY, ALL, SOME의 조합

다음은 매니저가 아닌 직원을 추출하는 예이다.

SELECT OBJECT(employee)
FROM EmployeeBean AS employee
WHERE employee.id NOT IN
    (SELECT employee2.id
     FROM ManagerBean AS employee2)

다음은 Subquery 결과값이 없는지 테스트하는 NOT EXISTS 연산자의 예이다("NOT"은 값이 있는지를 테스트하기 위해 제거될 수 있다).

SELECT OBJECT(cust)
FROM CustomerBean AS cust
WHERE NOT EXISTS
    (SELECT order.cust_num
     FROM OrderBean AS order
     WHERE cust.num = order.cust_num)

위 질의의 결과는 주문을 하지 않은 모든 고객의 명단이 된다.

마지막 예는 상호 연관된(correlated) 질의라고 할 수 있는데, 그 이유는 Subquery의 결과가 상위 질의의 파라미터로 반영되어야 하기 때문이다. 의존 관계가 없는 질의를 비상호 연관(uncorrelated) 질의라고 한다.

다음의 예는 UNIQUE 연산자의 사용을 보여주고 있다. 이 연산자는 result set의 row 중 중복된 것이 있는지를 확인한다. 0개 또는 1개의 row이거나, Subquery의 결과 내에 있는 모든 레코드가 유일하다면 true를 리턴한다. 이 연산자에 NOT을 붙이면 반대의 결과를 얻게 된다.

SELECT OBJECT(cust)
FROM CustomerBean AS cust
WHERE UNIQUE
    (SELECT cust2.id FROM CustomerBean AS cust2)

다음은 ">" 연산자의 예로서, 다른 연산자와 마찬가지로 Subquery의 결과값과 사용될 수 있다.

SELECT OBJECT(employee)
FROM EmployeeBean AS employee
WHERE employee.salary >
    (SELECT AVG(employee2.salary)
     FROM EmployeeBean AS employee2)

위의 JEUS EJB QL 질의는 평균 월급보다 많이 받는 모든 고용인의 결과를 리턴한다.

참고로 ANY, ALL, SOME이 사용되지 않는 경우에는 반드시 한 개의 값만이 Subquery의 결과로 리턴되어야 한다(이 경우에서는 평균 월급). ANY, ALL, SOME 연산자는 하나의 값보다 더 많은 값을 리턴하는 Subquery에 사용한다. 이 연산 작업은 다음과 같이 해석할 수 있다.

  • <Operand> <arithmetic operator> ANY <subquery>

    subquery의 결과 중 적어도 한 개의 값이 true를 리턴하면 true를 리턴한다.

  • <Operand> <arithmetic operator> SOME <subquery>

    "ANY"와 같은 의미를 가진다.

  • <Operand> <arithmetic operator> ALL <subquery>

    Subquery의 결과 모두가 true를 리턴해야 true를 리턴한다.

    참고

    XML DD 파일에 ">"와 "<" 문자를 넣으려 할 때는 CDATA 부분에 포함시켜야 한다. 그렇지 않으면 XML Parser가 혼동을 일으키고 XML 태그 지정문자로 인식한다.


JEUS EJB QL Extension ResultSet

JEUS EJB 엔진은 복수 컬럼인 java.sql.ResultSet 객체를 반환하는 ejbSelect() 질의를 지원한다. 그러므로 ejbSelect 메소드의 SELECT 문 안에 콤마(,)로 구분된 Target 필드의 목록을 지정할 수 있다.

SELECT employee.name, employee.id, employee.salary 
FROM EmployeeBean AS employee

위의 질의는 모든 EmployeeBean Instance의 name, id, salary로 구성된 java.sql.ResultSet을 생성한다. 이 ResultSet은 "name", "id", "salary"의 컬럼으로 구성된 레코드를 포함하게 된다. 이 ResultSet의 각 레코드는 해당하는 Entity Bean Instance를 표현한다. ResultSet들은 <cmp-field> 값(Bean이나 relationship filed가 아닌)만을 반환한다.

참고

ejbSelect() 메소드를 사용해서 java.sql.ResultSet 종류의 객체를 얻어와 모든 작업을 마쳤을 때에는 ResultSet.close()를 호출해야 한다. 이 close() 메소드는 EJB 엔진에 의해 자동적으로 호출되지 않는다.

JEUS EJB QL Extension Dynamic Query

JEUS EJB QL은 EJB QL 질의를 프로그램적으로 구현할 수 있도록 지원한다. 이것은 Instant EJB QL 기능으로 가능한 것이다. 본 절에서는 JEUS CMP 2.0에서 Instant EJB QL을 프로그래밍할 때 필요한 기본적인 사항들을 설명한다.

다음 코드에서는 CMP 2.0 Home Interface의 Instant EJB QL 사용법을 보여주고 있다. 이 코드는 순수하게 클라이언트 측의 것이다. 이 코드가 작동되도록 하려면 Instant EJB QL을 사용하도록 CMP Bean에 설정되어 있어야 한다. 이 부분에 대해서는 “8.3. Entity EJB 설정”을 참고한다.

import jeus.ejb.Bean.objectbase.EJBInstanceFinder;
import java.util.Collection;
. . .
Context initial = new InitialContext();
Object objref = initial.lookup("emp");
EmpHome home = (EmpHome)
    PortableRemoteObject.narrow(objref, EmpHome.class);
EJBInstanceFinder finder = (EJBInstanceFinder) home;
java.util.Collection foundBeans =
    finder.findWithInstantQL (“<EJB QL query sentence>”);
// Use foundBeans collection…
. . .

위 예에서의 <EJB QL query sentence>는 파라미터 없는 완전한 EJB QL 문장으로 대체되어야 한다("?"가 허용되지 않는다). 이 API에 대해서는 “Appendix B. Instant EJB QL API Reference”를 참고한다.

JEUS EJB QL Extension GROUP BY 키워드

JEUS EJB QL은 GROUP BYGROUP BY HAVING 절을 지원한다. 이들은 다음과 같이 작동한다.

  • <SELECT statement> GROUP BY <grouping column(s)>

    SELECT 문장이 실행되면 레코드들이 생성되고, GROUP BY 문장은 <grouping column(s)>에 지정된 컬럼(들)의 셋을 검색한다. 같은 값을 갖는 이 컬럼(들) 내의 모든 레코드들은 하나의 레코드로 합쳐지고 중복되는 것들은 버려진다.

    SELECT employee.departmentName
    FROM EmployeeBean AS employee
    GROUP BY employee.departmentName

    위 질의는 employee Bean의 유일한 모든 departmentName의 목록을 결과값으로 가진다.

  • <SELECT statement> GROUP BY <grouping column(s)> HAVING <condition>

    이런 형식의 문장은 이전에 설명한 예제와 같은 방식으로 동작하지만, <condition>에 설정된 것을 만족시키는 컬럼 그룹만이 포함된다.

    SELECT employee.departmentName
    FROM EmployeeBean AS employee
    GROUP BY employee.departmentName
    HAVING COUNT(employee.departmentName) >= 3

    위의 질의는 2개 이상의 EmployeeBean Instance가 발견된 모든 유일한 departmentName들의 목록을 반환한다(즉, 3 이상의 employee들을 가진 department의 목록).

예를 들어 [Table 1]의 데이터에 EJB QL 질의를 실행시키면 [Table 2]와 같은 결과가 출력된다.

[Table 1]

[Table 2]

이 결과는 HAVING 조건이 적어도 3개의 레코드를 가진 컬럼 그룹을 포함시켜야 한다고 명시되었기 때문이다. 더 자세한 GROUP BY, GROUP BY HAVING 절에 대한 정보는 SQL 문서들을 참고한다.

참고

JEUS EJB QL에서는 GROUP BY와 GROUP BY HAVING 문장을 Subquery 또는 최상위의 질의에서 사용할 수 있다. 후자의 경우에는 java.lang.String 객체의 집합이 리턴된다. 최상위의 GROUP BY와 GROUP BY HAVING 문장은 Bean 객체를 리턴할 수 없다.

본 절에서는 JEUS의 Entity EJB 성능 튜닝 방법에 대해서 자세히 설명한다. 튜닝 방법들은 “제4장 EJB의 공통 특성”“제7장 Session Bean”의 "object management"에서 제공한 방법들과 함께 Entity Bean에 적용할 수 있다.

모든 Entity Bean의 성능 튜닝에 공통적으로 필요한 설정은 다음과 같다.

  • 엔진 메인 모드 선택과 클러스터링 적용 여부

  • Entity Cache 크기 설정

  • DB 벤더 설정

다음은 모든 Entity Bean의 성능 튜닝을 위한 설명이다.

엔진 메인 모드 선택과 클러스터링 적용 여부

다음은 <engine-type>을 선택할 때와 몇 개의 EJB 엔진에 EJB를 클러스터링할지를 선택할 때 주요 판단 기준이 될 수 있는 규칙을 정리한 표이다.

물론 Entity Bean의 DB 데이터가 외부의 WAS가 아닌 컴포넌트에 의해 변경되는 환경에서는 SINGLE_OBJECT나 MULTIPLE_OBJECT를 사용해야 한다. 그리고 Failover를 위해서는 Bean을 클러스터링해야 한다.

SINGLE_OBJECT와 MULTIPLE_OBJECT 모드 중 하나를 선택할 때 마지막으로 고려해야 할 사항은 대상 Bean의 트랜잭션 처리시간이다(즉, Bean 내부에서 트랜잭션이 시작하고 commit되어 끝날 때까지의 평균시간). 그 시간이 아주 길면 MULTIPLE_OBJECT 모드를 선택하기를 권장하고, 이 모드에서 사용 가능한 동시성을 사용해야 한다. 그 시간이 반대로 짧으면 SINGLE_OBJECT 모드 사용을 권장한다.

만약에 위의 "규칙"이 준수되면 EJB 엔진은 최적의 성능으로 ejbLoad()를 호출할 수 있다.

참고

위의 테이블에서 사용된 "자주 사용되는", "보통으로 사용되는", "조금 사용되는"의 의미를 명확하게 정의할 수 없다. 약간의 직관력과 많은 테스트가 주어진 환경에 최적의 설정을 찾는 방법일 것이다.

Entity Cache 크기 설정

Entity Cache는 passivate된 Entity Bean Instance들의 저장소 역할을 한다. Instance들은 Entity Bean이 다시 Activate가 되면 Cache에서 나오게 된다.

<entity-cache-size> 크기를 크게(수백 개의 Instance가 수용되도록) 설정하면 passivate된 Bean들이 다시 Activate될 때 새로운 Entity Bean Instance들이 생성되지 않아도 되므로 성능이 좋아질 것이다. 그러나 메모리 관리가 가장 중요한 사항이라면 이 값을 적게 주거나 아예 사용하지 않도록 한다(값이 '0'이면 Entity Cache를 사용하지 않는다).

DB 벤더 설정

<db-vendor> 태그를 올바르게 설정한다. 모든 경우는 아니지만 어떤 상황에서는 Oracle과 같은 벤더의 제품을 위해서 EJB 엔진이 DB와의 연결을 최적화시킨다. 이 태그에 사용할 수 있는 DBMS 벤더의 이름 값들은 "JEUS XML Reference"의 "제11장.domain.xml EJB 엔진 설정"을 참고한다.

다음은 CMP 1.1/2.0 튜닝에 대한 설명이다.

엔진 Sub-mode 선택

CMP Bean을 사용할 때 <subengine-type>을 선택하면 EJB 엔진이 ejbLoad(), ejbFInd() 메소드를 최적화해서 사용할 수 있다.

<subengine-type>을 선택하는 주요 기준은 다음과 같다.

  • CMP Bean이 읽기 작업을 쓰기 작업보다 더 많이 할 것이라 예상되면 ReadLocking 모드를 사용한다.

  • CMP Bean이 쓰기 작업을 읽기 작업보다 더 많이 할 것이라 예상되면 WriteLocking 또는 WriteLockingFind 모드를 사용한다.

Fetch Size 설정

시스템 메모리의 과용을 감수하더라도 높은 성능을 원한다면 CMP Bean의 <fetch-size> 태그를 시스템 메모리의 과용을 감수하더라도 높게 설정해야 한다. 큰 값을 설정하면 매 호출마다 많은 양의 데이터를 읽어오기 때문에 네트워크를 효과적으로 사용할 수 있다. 그러나 EJB 엔진은 많은 양의 데이터를 Caching해야 하기 때문에 시스템 자원을 많이 소모하게 되어 각 호출에 대한 대기시간이 증가한다.

반대의 경우 만약 시스템 메모리의 절약이 높은 우선순위를 가지고 느린 네트워크 속도를 감수할 수 있다면 이 값을 상대적으로 낮게 설정한다. 기본값은 "10"이다. 대부분의 경우 "100"은 높은 값이고 "10"보다 낮은 값은 낮은 값으로 생각할 수 있다.

Initial Caching 설정

높은 운영 성능을 위해 많은 시스템 메모리 사용을 감수할 수 있다면, CMP Bean의 <init-caching> 값을 true로 설정한다. 이렇게 설정하면 EJB 엔진이 기동(Booting)할 때 모든 DB의 레코드들이 읽혀져 Entity Bean Instance로 전달된다. 결과적으로 엔진 기동(Booting) 시간이 오래 걸리겠지만, 처음의 접근시간을 훨씬 줄일 수 있다.

반대의 경우 만약 시스템 메모리의 절약 또는 빠른 엔진 기동(Booting)시간이 우선이라면 이 값은 false로 설정해야 한다. 만약 DB 테이블이 EJB에 아주 많이 매핑되어 있는 경우(수백, 수천 레코드)에는 <init-caching>가 false로 설정되어야 할 것이다. 그러나 EJB가 read-only(ejbLoad()가 한 번만 호출되는 것을 암시)라면 이 옵션을 강력히 추천한다.

EJB 코드, 표준 EJB DD, JEUS DD가 함께 설정되고 작동될 수 있는지 보여주기 위해 본 절에서는 완전한 CMP 2.0 Bean의 예를 제시한다. 이 예제는 책을 개념으로 모델화한 Book EJB이다.

기본적으로 모든 예에 주석을 달지 않았고 CMP 2.0 Bean이 jeus-ejb-dd.xml에 설정하는 방법만 보여준다. 예제를 deploy하려면 패키징 후에 EJB로 deploy한다. 자세한 내용은 “제3장 EJB 모듈”을 참고한다.

JEUS의 ejb-jar.xml에서 EJB QL 사용 예는 본 절의 "Jakarata EE EJB DD"를 참고한다.

Remote Interface


Home Interface


Bean Implementation


Jakarta EE EJB DD

[예 8.17] Jakarta EE EJB DD : <<ejb-jar.xml>>

<?xml version="1.0"?>
<ejb-jar version="3.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd">
   <enterprise-Beans>
      <entity>
         <ejb-name>BookBean</ejb-name>
         <home>test.book.BookHome</home>
         <remote>test.book.Book</remote>
         <ejb-class>test.book.BookEJB</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.String</prim-key-class>
         <reentrant>false</reentrant>
         <cmp-version>2.x</cmp-version>
         <abstract-schema-name>Book</abstract-schema-name>
         <cmp-field><field-name>code</field-name></cmp-field>
         <cmp-field><field-name>title</field-name></cmp-field>
         <cmp-field><field-name>author</field-name></cmp-field>
         <cmp-field><field-name>price</field-name></cmp-field>
         <cmp-field><field-name>publisher</field-name></cmp-field>
         <primkey-field>code</primkey-field>
             <query>
                 <query-method>
                     <method-name>findByTitle</method-name>
                     <method-params>
                         <method-param>
                             java.lang.String
                         </method-param>
                     </method-params>
                 </query-method>
                 <ejb-ql>
                     SELECT OBJECT(b) FROM Book b
                     WHERE b.title = ?1 ORDERBY b.price
                 </ejb-ql>
             </query>
             <query>
                 <query-method>
                     <method-name>findInRange</method-name>
                     <method-params>
                        <method-param>
                            java.lang.String
                        </method-param>
                        <method-param>
                            java.lang.String
                        </method-param>
                    </method-params>
                </query-method>
                <ejb-ql>
                    SELECT OBJECT(b) FROM Book b
                    WHERE b.title BETWEEN ?1 AND ?2
                </ejb-ql>
            </query>
            <query>
                <query-method>
                    <method-name>findAll</method-name>
                    <method-params/>
                </query-method>
                <ejb-ql>
                 SELECT OBJECT(b) ORACLEHINT '/*+ALL_ROWS*/' FROM Book b
                </ejb-ql>
            </query>
       </entity>
    </enterprise-Beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>BookBean</ejb-name>
                <method-name>*</method-name>
                <method-params/>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>


참고

굵은 글자의 3줄이 비표준의 JEUS 전용 EJB QL이다("ORDERBY", "BETWEEN", "ORACLEHINT").

JEUS EJB DD