2012-12-04 6 views
3

약 10 개의 EntityManagers가있는 Java EE 응용 프로그램이 있습니다 (EM 수가 증가 할 것입니다). 또한 내 애플리케이션에는 많은 stateless, statefull 및 message driven beans가 포함되어있다.Java EE 응용 프로그램에서 여러 EntityManager 처리

각각의 빈에 내 EM을 @PersistenceContext (그리고 어떤 EM을 사용자에게 사용할지 감지하는 2 가지 방법)으로 주입하는 대신, 모든 것을 싱글 톤 빈 내에 저장하고 다른 빈들과 액세스 할 수 있습니다. 그처럼 유지 보수에 대한 걱정은 없습니다.

그럼에도 불구하고 하나의 싱글 톤 빈 안에 EM을 저장하는 것이 스레드로부터 안전합니까? 병목 현상이 나타날 수 있습니까?

또 다른 해결책은 추상 클래스를 만들고 모든 콩이이를 확장한다는 것입니다.

더 나은 솔루션은 무엇입니까?

답변

2

컨테이너 관리 엔티티 관리자는 현재 JTA 트랜잭션과 함께 자동으로 전파되며 동일한 지속성 단위에 매핑 된 EntityManager 참조는 해당 트랜잭션 내의 지속성 컨텍스트에 대한 액세스를 제공합니다. 따라서 동시성 문제를 제외하고는 싱글 톤에서 엔티티 관리자를 공유하는 것이 좋지 않습니다. 콩에서 호출하는 모든 메소드에 대해 동일한 트랜잭션 컨텍스트를 사용하게됩니다.
간단한 해결책은 콩에 EntityManagerFactory 참조를 삽입하고 createEntityManager() 메서드를 호출하는 EntityManager 개체를 만드는 것입니다. 단점은 트랜잭션을 수동으로 관리해야하며 더 이상 컨테이너에 의존하지 않아야한다는 것입니다.
다른 방법으로는 기본 엔터프라이즈 bean에 모든 엔티티 관리자를 주입하고 적절한 관리자를 전달하는 메소드로 서비스 bean에 비즈니스 로직을 구현할 수 있습니다. 후자 솔루션의 예 :

@Stateless 
class MainBean { 
    @PersistenceContext EntityManager em1; 
    @PersistenceContext EntityManager em2; 
    ... 
    @EJB WorkerBean1 workerBean1; 
    @EJB WorkerBean2 workerBean2; 
    ... 
    void method1(Object param1, Object param2) { 
     workerBean1.method1(em1, param1, param2); 
    } 

    void method2(Object param1, Object param2, Object param3) { 
     workerBean2.method2(em2, param1, param2, param3); 
    } 
    ... 
} 

@Stateless 
class WorkerBean1 { 
    void method1(EntityManager em, Object param1, Object param2) { 
     ... 
    } 
    ... 
} 

@Stateless 
class WorkerBean2 { 
    void method2(EntityManager em, Object param1, Object param2, Object param3) { 
     ... 
    } 
    ... 
} 
+0

감사합니다. 좋습니다, 그래서 컨테이너 트랜잭션을 기반으로하기 때문에'EntityManagerFactory'의 싱글 톤과 인젝션을 잊어 버려야합니다. 내가 잘 이해하면 각 콩에있는 모든 EM을 복사하라고 충고하겠습니까? 유지 보수 문제를 피하고 싶습니다. 그것이 사실이 아니라면 더 나은 설명 주셔서 감사합니다. –

+1

예, 컨테이너 관리 트랜잭션을 사용하려는 경우 이는 유일한 방법입니다. 그것은 싱글 톤에서 엔티티 관리자를 선언하는 것과 정말로 다르지 않습니다. 모든 엔티티 관리자와 함께 싱글 톤이 아닌 고유 한 엔터프라이즈 빈을 개발하여 어댑터 설계 패턴을 적용 할 수 있습니다 (관리자를 추가하거나 제거 할 때 단일 지점을 수정할 수 있습니다). 이 bean은 모든 엔 터프 라이즈와 메소드 호출을 다른 엔터프라이즈 빈에 라우트하여 적절한 엔티티 관리자를 전달합니다. 불행히도 단점은 후자의 엔터프라이즈 bean 메소드가 관리자를 매개 변수로 포함해야한다는 것입니다. – remigio

+0

다른 콩은 모든 EM이 저장되는 고유 한 콩을 확장 할 것입니다. EM이 하드 코딩 된 고유 한 장소를 갖고 싶습니다. 영어는 제 언어가 아니며 때로는 기술 용어를 이해하는 데 문제가 있습니다. 용서하십시오. –

4

매니저가 당신이 싱글을 통해 사람을 공유해서는 안, 스레드 안전 있어야되지 엔티티. 엔티티 관리자를 서블릿에 삽입하지 않아야하는 이유와 그러한 웹 구성 요소에서 JNDI를 조회하는 이유가 시간이 지남에 따라 엔티티 관리자의 다른 인스턴스를 반환해야하는 것과 같은 이유입니다.

실제로 일부 구현은 스레드 안전 인 엔티티 관리자를 제공 할 수 있으므로 테스트하는 동안 작동하는 것처럼 보일 수 있습니다. 그러나 이식성을 높이고 업그레이드시의 불이익으로부터 보호하기 위해 절대로이 소프트웨어를 신뢰해서는 안됩니다. 대신 공통 기본 클래스에서 상속의

, 당신은 하나의 빈에서 모든 엔티티 관리자를 정의하고, 당신이 하나의 엔티티 관리자를 필요로 어디든지 있음을 주입 할 수있다.

예.

@Stateless 
public class EntityManagerProviderBean { 

    @PersistenceContext(unitName="foo") 
    private EntityManager entityManagerFoo; 

    @PersistenceContext(unitName="bar") 
    private EntityManager entityManagerBar; 

    public EntityManager getEntityManager() { 
     return ...? entityManagerFoo : entityManagerBar; 
    } 
} 

(여기서 ... 논리가 당신이 바로 엔티티 관리자를 선택하는 데 사용할 것입니다)

는 엔티티 관리자가 필요한 빈에이 주입 : 또는

@Stateless 
public class MyService { 

    @EJB 
    private EntityManagerProviderBean entityManagerProvider; 

    public void doStuff(MyEntity myEntity) { 
     entityManagerProvider.getEntityManager().update(myEntity); 
    } 

} 

을 다음과 아마도 더 깨끗할 것입니다 :

@Stateless 
@PersistenceContexts({ 
    @PersistenceContext(unitName="foo", name = "fooENC"), 
    @PersistenceContext(unitName="bar", name = "barENC") } 
) 
public class EntityManagerProviderBean { 

    @Resource 
    private EJBContext context; 

    public EntityManager getEntityManager() { 
     return (EntityManager) context.lookup(... ? "fooENC" : "barENC"); 
    } 
} 

T 마지막 예제는 모든 영속 컨텍스트를 빈의 ENC로 매핑하는데, ​​여기서 이들은 프로그래밍 방식으로 편리하게 검색 될 수있다.

불행히도 사람들은 후자의 구문에 대한 테스트를 TCK에 추가하는 것을 잊었고 이후 주요 공급 업체는이를 구현하는 것을 잊어 버렸습니다 (http://java.net/jira/browse/JPA_SPEC-38https://issues.jboss.org/browse/AS7-5549 참조). 따라서 이것이 서버에서 작동하는지 테스트하십시오.

+0

IBM WAS가 (EntityManager) context.lookup ("blah")을 처리하는 방법을 알고 있습니까? EntityManager는 매번 새로운 URI (PU 당 1 EMF)를 반환합니까, 아니면 매번 같은 EM입니까 (PU 당 1 EM)? 첫째로 좋을 것이고, 두 번째는 끔찍할 것입니다. 하지만 어디서나 답을 찾을 수는 없습니다. – djb

0

복합 지속성 단위 - 자바 EE 자바 EE

여러 엔티티 관리자를 처리하는 방법, 즉 다수의 지속성 단위 복합 지속성 유닛 (CPU에)를 사용하는 것이다. 이러한 복합 지속 단위는 데이터 계층 인 EE 웹 응용 프로그램의 단일 지점에서 평가할 수 있습니다. @PersistenceContext을 사용하려면 @Stateless EE Bean이되어야합니다.

다양한 Java 응용 프로그램에서 재사용 가능한 엔티티 클래스를 만들 수있는 복합 지속성 단위가 도입되었습니다. CPU는 엔터프라이즈 아키텍처의 기능입니다. 쇼케이스로 EclipseLink를 사용하기로 결정했습니다. 실행중인 프로덕션 애플리케이션에서 긍정적 인 경험을했기 때문입니다.

어떤 경우에는 소개

는, 엔티티는 서버 풍경에서 더 많은 웹 서비스 전반에 걸쳐 필요한 일반적인 데이터가 포함되어 있습니다. 예를 들어 일반적인 '이름 주소'엔티티, '사용자 비밀번호 역할'엔티티, '문서 키워드 색인'엔티티 등을 예로들 수 있습니다. 복합 영속 단위 구현은 각 엔티티 정의의 소스가 단 한 곳 ('정의의 단일 지점'). 이 엔티티 정의는 이후이 엔티티 액세스가 필요한 각 Java 웹 응용 프로그램에 포함될 수 있습니다. 복합 퍼시스턴스 유닛의 작용은 다음 가이드에 의해 도시된다

복합 지속성 유닛

사용 : 복합 지속성 유닛 EclipseLink composite persistence units

개념은 제 부재 유닛 지속성 정의하여 작동한다. 각 구성원 지속성 단위는 다른 데이터베이스와 연관 될 수 있지만 구성원 지속성 단위는 모두 동일한 실제 데이터베이스를 참조 할 수도 있습니다. EclipseLink (버전 2.6.4)가 하나의 Postgress 데이터베이스와 함께 사용 된 후자에 대한 경험이 있습니다.

필요한 모듈 방식을 사용하려면 Maven이 필요합니다. 다음

설정은이 persistence.xml

된 복합 지속성 부 부재 정의된다 : 전용 메이븐 모듈 관련 기관 하나씩 (자바 @Entity 클래스)의 프로그램 군. 이 Maven 모듈에 복합 영속 단위 멤버 (중요!)도 정의하십시오. 복합 단위 구성원 PuPersonData은 개인 데이터를 특징 짓는 관련 엔티티 집합을 나타냅니다. 멤버 영속성 단위 PuPersonData를 (

<persistence-unit name="PuPersonData" transaction-type="JTA"> 
... 
    <jta-data-source>jdbc/PostgresDs</jta-data-source> 
... 

)으로 정의하십시오. 제 메이븐 모듈

은 다른 복합 지속성 부 부재 PuWebTraffic (

<persistence-unit name="PuWebTraffic" transaction-type="JTA"> 
... 
    <jta-data-source>jdbc/PostgresDs</jta-data-source> 
... 

)를 정의한다.웹 트랜잭션, 로그온, 세션 등에 관한 데이터를 저장하는 다른 엔티티 (@Entity으로 표시된 Java 클래스)를 포함하십시오. 두 복합 엔티티 단위 구성원은 엔티티에 대해 분리되어 있어야하며 엔티티에서 겹침이 허용되지 않아야합니다 - 이름.

<properties> 
    <property name="eclipselink.composite-unit.member" value="true"/> 
    ... 
</properties> 

복합 지속성

우리는 지금 세 번째 메이븐에서 정의하는 단위가 모두 포함하는 복합 지속성 단위 CPuPersonSessionData를 모듈 :

두 퍼시스턴스 유닛 회원들은 XML-정의에 속성이 퍼시스턴스 유닛 멤버 PuPersonData 및 PuWebTraffic.

<persistence-unit name="CPuPersonSessionData" transaction-type="JTA"> 

지속성이 합성 부 CPuPersonSessionData 두 속하는 메이븐 모듈의 편집 결과 인 병 등의 수단에 의해 두 지속성 유닛 멤버와 PuPersonData PuWebTraffic을 말한다. 복합 지속성 유닛의 XML-정의에서

... 
    <jar-file>PuPersonData.jar</jar-file> 
    <jar-file>PuWebTraffic.jar</jar-file> 
... 

다음 속성을 설정해야

<properties> 
    <property name="eclipselink.composite-unit" value="true"/> 
    ... 
</properties> 

이 설정 복합 지속성 유닛 지속성 부보다 자바 EE 다르게 처리되는 것을 보장 회원. 저장하고 개인 데이터와 트래픽 데이터를 모두 개체를 검색하는 것입니다 자바 웹 응용 프로그램에서

자바에서 퍼시스턴스 유닛의

사용은 단지 복합 퍼시스턴스 유닛이 포함되어

@Stateless 
public class DataLayer { 

    @PersistenceUnit(unitName="CPuPersonSessionData") 
    EntityManager em; 
    ... 

이제 persist, findmerge과 같은 일반 'em'연산을 복합 엔티티 구성원 중 하나에 포함 된 각 엔티티에서 수행 할 수 있습니다.

Payara에서는이 복합 영속 단위가 각 영속 단위 구성원과 관련된 엔티티를 처리하는 데 XA 트랜잭션이 필요하지 않았습니다.

메이븐

메이븐 부모 POM 파일은 관련 모듈에 대한 사양을 포함 할 필요가있다.

... 
    <modules> 
      <module>PersonData</module> 
      <module>WebTraffic</module> 
      <module>PersonSessionData</module> 
    </modules> 
... 

각 모듈의 POM 파일은 부모 POM 파일을 참조하여 일반적인 Maven 프로젝트로 구성되어야합니다.

함정 :

  • 당신은 다소 까다로운 일이 될 수있는, 제대로 메이븐 멀티 모듈 프로젝트를 구성해야합니다. 각 복합 지속성 유닛 멤버는 별도의 Maven 모듈을 구성합니다. 또한 복합 영속 단위는 별도의 Maven 모듈입니다. 회원은 먼저 Maven 순서로 컴파일해야합니다.
  • 복합 지속 유닛의 모듈을 컴파일 할 때 복합 지속 유닛의 '병'을 찾아야합니다.
  • 각 복합 영속 단위 구성원의 엔티티는 생성 된 'jar'에서 직접 'classes'디렉토리에서 사용할 수 있어야합니다 (Maven을 통해 엔티티에 대한 추가 경로를 추가하는 것은 가능하지만 복잡합니다).
  • 복합 영속 단위가 '영속 단위'의 'jars'를 사용할 수 있어야 복합 영속 단위가이를 찾을 수 있습니다.

이득은 재사용 가능한 엔티티와 함께 ​​작동하는 깔끔한 엔터프라이즈 데이터 레이어로, 각각 하나의 중심 정의가 있습니다. 또한 교차 단위 원시 SQL 쿼리를 수행 할 수도 있습니다. 나는이 일을 또한 얻었다.

복합 지속성 단위 구성원이 다른 실제 데이터베이스에서 실행될 때 교차 단위 기본 쿼리가 작동하지 않는다고 명시된 문서에는 이것은 여전히 ​​검증되어야합니다.

관련 문제