Korrekte Verwendung von Stateful Beans mit Servlets

8

Wir haben derzeit eine Stateful-Bean, die in ein Servlet injiziert wird. Das Problem ist, dass wir manchmal eine Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] erhalten, wenn wir eine Methode für die Stateful Bean ausführen.

%Vor%

Im obigen Code überprüft constructReport , ob eine neue Verbindung zu der im Report angegebenen Datenbank geöffnet werden muss, nach der ein Bericht in HTML aus einer Abfrage erstellt wird, die aus den angegebenen Parametern besteht.

>

Der Grund, warum wir uns für die Verwendung einer Stateful-Bean gegenüber einer Stateless-Bean entschieden haben, war, dass wir eine Datenbankverbindung zu einer unbekannten Datenbank öffnen und Abfragen durchführen müssen. Bei einem statuslosen Bean scheint es ineffizient zu sein, Datenbankverbindungen mit jeder injizierten Instanz der Bean wiederholt zu öffnen und zu schließen.

    
Burmudar 20.12.2009, 07:53
quelle

5 Antworten

9

Dies ist nicht der Fall, für den Stateful Session Beans (SFSB) verwendet werden sollen. Sie dienen dazu, den Conversation-Status zu halten und sind an die HTTP-Sitzung des Benutzers gebunden, um diesen Status zu speichern, wie eine schwergewichtige Alternative zum direkten Speichern des Status in der Sitzung.

Wenn Sie Dinge wie Datenbankverbindungen speichern möchten, gibt es bessere Möglichkeiten, dies zu tun.

Die beste Option ist die Verwendung eines Verbindungspools. Sie sollten immer einen Verbindungspool verwenden, und wenn Sie innerhalb eines Anwendungsservers arbeiten (was bei Verwendung von EJBs der Fall ist), können Sie die Datenquellenkonfiguration Ihres Anwendungsservers problemlos verwenden Erstellen Sie einen Verbindungspool und verwenden Sie diesen in Ihrer statuslosen Session-Bean (SLSB).

    
skaffman 20.12.2009, 09:32
quelle
14

Einige weitere Details zur ConcurrentAccessException : gemäß der EJB-Spezifikation Der Zugriff auf SLSB wird von der App synchronisiert. Server. Dies ist jedoch bei SFSB nicht der Fall. Die Last, sicherzustellen, dass der SFSB nicht gleichzeitig aufgerufen wird, liegt auf der Hand des Anwendungsentwicklers.

Warum? Nun, die Synchronisation von SLSB ist nur auf Instanzebene notwendig. Das heißt, jede bestimmte Instanz des SLSB ist synchronisiert, aber Sie können mehrere Instanzen in einem Pool oder auf einem anderen Knoten in einem Cluster haben, und gleichzeitige Anfragen auf verschiedenen Instanzen sind kein Problem. Dies ist bei SFSB leider nicht so einfach, da Instanzen und Replikation im gesamten Cluster passiviert / aktiviert werden. Deshalb erzwingt die Spezifikation dies nicht. Werfen Sie einen Blick auf diese Diskussion , wenn Sie sich für das Thema interessieren.

Dies bedeutet, dass die Verwendung von SFSB aus dem Servlet kompliziert ist. Ein Benutzer mit mehreren Fenstern aus derselben Sitzung oder das erneute Laden der Seite vor dem Rendern kann zu einem gleichzeitigen Zugriff führen. Jeder Zugriff auf das EJB, der in einem Servlet erfolgt, muss theoretisch auf der Bean selbst synchronisiert werden. Was ich gemacht habe, war ein InvocationHandler um alle zu synchronisieren Aufrufe an die jeweilige EJB-Instanz:

%Vor%

}

Dann, direkt nachdem Sie die Remote-Referenz auf das EJB erhalten haben, wickeln Sie es mit dem SynchronizationHandler ein. Auf diese Weise können Sie sicher sein, dass auf diese bestimmte Instanz nicht gleichzeitig mit Ihrer App zugegriffen wird (solange sie nur in einer JVM ausgeführt wird). Sie können auch eine reguläre Wrapper-Klasse schreiben, die alle Methoden der Bean synchronisiert.

Meine Schlussfolgerung ist trotzdem: benutze SLSB wann immer möglich.

BEARBEITEN :

Diese Antwort gibt die EJB 3.0-Spezifikationen (Abschnitt 4.3.13) wieder:

  

Clients dürfen nicht gleichzeitig eine statusbehaftete Sitzung aufrufen   Objekt. Wenn eine vom Client aufgerufene Geschäftsmethode in einem Prozess ausgeführt wird   Instanz, wenn ein anderer vom Client aufgerufener Aufruf vom selben oder vom anderen Aufruf stammt   Client, kommt an derselben Instanz einer Stateful-Session-Bean-Klasse an,   Wenn der zweite Client ein Client der Business-Schnittstelle der Bean ist,   Gleichzeitiger Aufruf kann dazu führen, dass der zweite Client den Befehl erhält   javax.ejb.ConcurrentAccessException

Solche Einschränkungen wurden in EJB 3.1 (Abschnitt 4.3.13) entfernt:

  

Standardmäßig können Clients gleichzeitige Aufrufe an einen Stateful-Server ausführen   Session-Objekt und der Container ist erforderlich, um solche zu serialisieren   gleichzeitige Anfragen.

     

[...]

     

Der Bean-Entwickler kann optional diesen gleichzeitigen Client angeben   Anfragen an eine Stateful Session Bean sind verboten. Dies geschieht mit   der @AccessTimeout-Annotation- oder Access-Timeout-Implementierungsdeskriptor   Element mit einem Wert von 0. In diesem Fall, wenn ein Client aufgerufenen Geschäft   Methode wird für eine Instanz ausgeführt, wenn ein anderer vom Client aufgerufener Aufruf   von demselben oder einem anderen Client, kommt an derselben Instanz von a an   Stateful Session Bean, wenn der zweite Client ein Client der Bean ist   Business-Schnittstelle oder No-Interface-Ansicht, der gleichzeitige Aufruf   muss dazu führen, dass der zweite Client eine erhält   javax.ejb.ConcurrentAccessException

    
ewernli 20.12.2009 10:29
quelle
1

Bis Sie Code und StackTrace bereitstellen, sollten Sie einen Verbindungspool . Wenn unter "unbekannte Datenbank" eine Datenbank verstanden wird, deren Parameter vom Endbenutzer bereitgestellt werden und daher kein vorkonfigurierter Verbindungspool möglich ist, können Sie weiterhin das Verbindungspoolkonzept verwenden und nicht jedes Mal eine neue Verbindung öffnen.

Auch theck dieser Thread .

    
Bozho 20.12.2009 08:54
quelle
0

Session-Beans können nicht gleichzeitig verwendet werden, wie skaffman gesagt hat, dass sie mit einem Zustand korrespondieren sollten, der der Client-Sitzung entspricht, und normalerweise im Session-Objekt pro Client gespeichert sind.

Das Refactoring zur Verwendung eines Datenbankpools zur Verarbeitung gleichzeitiger Anfragen an Ihre Ressourcen ist der richtige Weg.

In der Zwischenzeit, wenn Sie nur diese triviale Verwendung benötigen, können Sie den Aufruf von constructReport wie folgt synchronisieren:

%Vor%

Beachten Sie, dass dies keine Lösung ist, wenn constructReport relativ zu Ihrer Anzahl von Clients eine erhebliche Zeit benötigt.

    
rsp 20.12.2009 09:48
quelle
0

Sie sollten den Servlet- oder Ejb-Zugriff niemals synchronisieren, da dies die Queue der Anforderungswarteschlange verursacht, und wenn Sie N Benutzer gleichzeitig haben, wird der letzte lange Zeit warten und oft eine Zeitüberschreitung erhalten !!! Syncronize-Methode ist aus diesem Grund nicht vorgesehen !!!

    
Achille 14.07.2011 07:19
quelle

Tags und Links