2009-12-20 6 views
8

현재 Servlet에 주입 된 Stateful Bean이 있습니다. 문제는 stateful 빈에서 메소드를 실행할 때 Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] 가끔 발생한다는 것입니다. 이 HTML에서 보고서가 지정된 파라미터에서 내장되어 쿼리로 구성되는 후 보고서에 지정된 데이터베이스에 대한 새 연결을 열 필요가있는 경우 위의 코드에서 서블릿으로 상태 유지 Bean의 올바른 사용

public class NewServlet extends HttpServlet { 
    @EJB 
    private ReportLocal reportBean; 

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException { 
     response.setContentType("text/html;charset=UTF-8"); 
     PrintWriter out = response.getWriter(); 
     try { 
      String[] parameters = fetchParameters(request); 
      out.write(reportBean.constructReport(parameters)); 
     } finally { 
      out.close(); 
     } 
    } 
} 

, constructReport 확인합니다.

스테이트 풀 빈에 스테이트 풀 빈을 사용하는 이유는 알 수없는 데이터베이스에 대한 데이터베이스 연결을 열어 쿼리를 수행해야하기 때문입니다. 상태없는 빈을 사용하면 주입 된 각 빈 인스턴스와의 데이터베이스 연결을 반복적으로 열고 닫는 것이 대단히 비효율적 인 것처럼 보입니다.

답변

9

이것은 상태 기반 세션 빈 (SFSB)이 사용되는 것이 아닙니다. 그것들은 대화 상태를 유지하도록 고안되었으며, 세션에 상태를 직접 저장하는 대신, 사용자의 http 세션에 바인드되어 그 상태를 유지해야합니다.

데이터베이스 연결과 같은 것을 보관하려면 더 좋은 방법이 있습니다.

가장 좋은 방법은 연결 풀을 사용하는 것입니다. 항상은 연결 풀을 사용하고 응용 프로그램 서버 (EJB를 사용하고 있다면 사용중인 경우)를 실행하는 경우 응용 프로그램 서버의 데이터 소스 구성을 사용하여 연결 풀을 쉽게 만들 수 있습니다. 무 상태 세션 빈 (SLSB) 내부에서 사용하십시오.

+0

AFAIK, 응용 프로그램 서버에서 데이터 원본을 만들 때 데이터베이스가 있음을 미리 알아야합니다. 위의 연결은 사용자가 지정해야하는 데이터베이스에 연결해야합니다. – Burmudar

+3

이것은 나에게 매우 불안전하게 보입니다. – duffymo

1

일부 코드와 스택 추적을 제공 할 때까지 connection pool을 사용하는 것이 좋습니다. "알 수없는 데이터베이스"란 최종 사용자가 매개 변수를 제공하고 미리 구성된 연결 풀이없는 데이터베이스를 의미하는 경우 매번 새 연결을 열지 않고도 연결 풀 개념을 계속 사용할 수 있습니다.

또한 theck this thread입니다.

0

세션 빈은 클라이언트 세션에 상응하는 상태를 처리하기위한 것으로서 클라이언트 당 세션 객체에 저장되는 것처럼, 동시에 사용할 수 없습니다.

데이터베이스 풀을 사용하여 자원에 대한 동시 요청을 처리하는 리팩토링이 필요합니다. 한편

, 당신이 필요로하는 모든이 사소한 사용하는 경우, 당신은 같이 constructReport에 대한 호출을 동기화 할 수 있습니다 : constructReport가 상대적인 시간의 상당한 양 걸리는 경우이 해결책이 없다는 것을

synchronised (reportBean) { 
     out.write(reportBean.constructReport(parameters)); 
} 

주 귀하의 고객 수.

14

ConcurrentAccessException에 대한 몇 가지 세부 정보 : EJB 사양에 따라 SLSB에 대한 액세스가 앱과 동기화됩니다. 섬기는 사람. 그러나 SFSB의 경우는 그렇지 않습니다. SFSB가 동시에 액세스되지 않도록하는 부담은 응용 프로그램 개발자의 어깨에 있습니다.

왜? 음, SLSB의 동기화는 인스턴스 수준에서만 필요합니다. 즉, SLSB의 특정 인스턴스가 동기화되지만 풀의 여러 인스턴스 또는 클러스터의 다른 노드에있을 수 있으며 서로 다른 인스턴스의 동시 요청은 문제가되지 않습니다.불행히도 SFSB를 사용하면 인스턴스를 비활성화/활성화하고 클러스터 전체에서 복제하므로 쉽지 않습니다. 이것이 스펙이 이것을 시행하지 않는 이유입니다. 주제에 관심이 있다면 this dicussion을보십시오.

즉, 서블릿에서 SFSB를 사용하는 것은 복잡합니다. 동일한 세션의 여러 창이있는 사용자 또는 렌더링이 완료되기 전에 페이지를 다시로드하면 동시 액세스가 발생할 수 있습니다. 서블릿에서 수행되는 EJB에 대한 각각의 액세스는 이론적으로 빈 자체에서 동기화되어야합니다. 내가 한 것은 특정 EJB 인스턴스의 모든 호출을 동기화하는 InvocationHandler를 만드는 것이 었습니다 : 당신은 EJB의 원격 참조를 취득 직후, 그리고

public class SynchronizationHandler implements InvocationHandler { 

private Object target; // the EJB 

public SynchronizationHandler(Object bean) 
{ 
     target = bean; 
} 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
    synchronized(target) 
    { 
     // invoke method to the target EJB 
    } 
    } 

}

, 당신은 SynchronizationHandler로 포장 . 이렇게하면 특정 인스턴스가 하나의 JVM에서만 실행되는 한 앱에서 동시에 액세스 할 수 없다는 것을 확신 할 수 있습니다. 또한 Bean의 모든 메소드를 동기화하는 일반 랩퍼 클래스를 작성할 수 있습니다.

그럼에도 불구하고 내 결론은 가능하면 SLSB를 사용하십시오.

편집 :

이 대답은 EJB 3.0 사양을 반영한다 (제 4.3.13는) :

클라이언트는 상태 유지 세션에 동시 통화 개체를 만들 수 없습니다. 클라이언트에서 다른 클라이언트 호출이 상태 세션빈 클래스의 동일한 인스턴스에 도착할 때 인스턴스에서 클라이언트가 호출 한 비즈니스 메소드가 진행중인 경우 두 번째 클라이언트가 클라이언트 인 경우 빈의 비즈니스 인터페이스는 동시 호출은 javax.ejb.ConcurrentAccessException

이러한 제한은 EJB 3.1에서 제거 된 (섹션 4.3.13)을 수신 번째 클라이언트가 발생할 수 있습니다 :

기본적으로 클라이언트는 상태 호출 세션 개체에 대한 동시 호출이며 컨테이너는 이와 같은 동시 요청을 에 직렬화해야합니다.

[...]

빈 개발자는 선택적으로 상태 유지 세션 빈에 요청이 금지되어 있습니다 동시 클라이언트 지정할 수 있습니다. 이 작업은 @AccessTimeout 주석 또는 액세스 타임 아웃 배포 설명자 요소의 값이 0 인 경우 수행됩니다.이 경우 클라이언트에서 호출 한 비즈니스 메서드가 다른 클라이언트 호출에 의해 인스턴스에서 진행 중이면 에서 두 번째 클라이언트가 빈의 비즈니스 인터페이스 또는 인터페이스 없음보기의 클라이언트 인 경우 상태 저장 세션 빈의 동일한 인스턴스에 도착하면 동시 호출 은 을 수신해야합니다 javax.ejb.ConcurrentAccessException

+0

JNDI 조회를 통해 SFSB에 대한 참조를 얻으면 동기화 할 필요가 없습니다. 맞습니까? 이 경우 Java EE 스펙은 각 조회에 대해 SFSB의 새 인스턴스가 리턴됨을 보장합니다. – fnt

+0

@fnt 조회마다 새 인스턴스가 반환되지만, 사용자가 설정 한대로 처리해야합니다. 컨테이너는 인스턴스에 대한 호출을 직렬화하지 않으므로 처리하지 않으면 ConcurrentAccessException으로 끝날 수 있습니다. – ewernli

+0

서블릿 인스턴스 필드 나 다른 공유 리소스가 될 수 있으므로 참조를 저장하지 않으면 매번 SFSB를 안전하게 검색하는 것으로 충분합니다. 이 경우에 설명 된 SynchronizationHandler는 불필요합니다. – fnt

0

서블릿 또는 ejb 액세스를 동기화하려고해서는 안됩니다. 왜냐하면이 원인이 큐를 요청하고 N 명의 동시 사용자가있는 경우 마지막 메시지가 오랜 시간 대기하고 종종 제한 시간 응답을 받게됩니다. Syncronize 방법은 이런 이유로 예정되지 않는다 !!!