Beispiel: IBM WebSphere-spezifische Concurrency Control
Aufbau des Beispiels
- Das Beispiel besteht aus einer Entity-Bean und einem Application Client.
- Die Entity-Bean hat zwei Felder "ID" und "COUNT".
- Es existiert nur eine Instanz, d.h. wenn der Anwendungsclient keine Instanz mit
der ID "100" findet, erzeugt er eine.
- Die Bean hat eine Methode "increment", in der der Wert des Felds "COUNT" gelesen wird.
Anschließend schläft sie 5 Sekunden und setzt danach den um 1 erhöhten Wert.
- Im Anwendungsclient werden zwei Threads gestartet, die parallel "increment" aufrufen.
D.h. beide werden den gleichen Wert für "COUNT" lesen und natürlich auch beide nach 5 Sekunden
Wartezeit den gleichen, um 1 erhöhten Wert zurückzuschreiben versuchen. Je nach Einstellung
des "Resource access intent" kann dies (fehlerhafterweise) klappen oder zu einer Exception führen.
- Damit wir ohne großes Umschalten mit den diversen Varianten spielen können, gibt
es im Moment drei "increment"-Methoden, benannt nach den "access intent"-Leveln, die für
sie eingestellt werden sollen. Auf Bean-Seite ergibt sich hierfür kein Unterschied im Code,
d.h. reines Copy&Paste ! Auf Clientseite gibt es entsprechend drei Threads, die jeweils die
entsprechende Bean-Methode aufrufen.
- Außerdem gibt es den Zugriff auch über zwei Session Beans "ConcurrencyTesterXXX". Eine
Variante arbeitet Stateless (Entity-Bean "Counter" wird erst beim Aufruf
der Geschäftsmethode gesucht), die andere Stateful ("Counter" wird im ejbCreate geholt,
in der Geschäftsmethode erfolgt NUR der Aufruf von increment). Der Aufruf erfolgt über
Buttons im Client.
Hier gibt es das WebSphere-Projekt als Projektaustausch-Export zum Download : ConcurrencyExport.zip
Konfiguration des Access Intent
Im EJB-Implementierungsdeskriptor geht man zur Registerkarte "Zugriff". Unter
"Wert für geplanten Zugriff auf Entities 2.x (Methodenstufe)" fügt man für jede der drei
"increment"-Methoden eine "access intent"-Definition zu.
In Schritt 1 des Assistenten gibt man der Zugriffsdefinition einen Namen (ich habe im Beispiel den
"access intent" verwendet) und wählt die Zugriffsart aus. Im Beispiel habe ich dies für
"wsOptimisticRead", "wsPessimisticUpdate-WeakestLockAtLoad" und "wsPessimisticUpdate-Exclusive" getan.
Man wählt die Bean aus.
Im letzten Schritt wird die zum Access intent passende Methode ausgewählt.
Ergebnisse
(Hinweis: am besten den Server jedesmal neu starten, da es wegen der fiesen Threads
manchmal zu Hängern kommt)
Aufruf der drei Methoden führt zu folgenden Ergebnissen:
- Direkter Aufruf von incrementPessimisticUpdateWeakestLockAtLoad: Der schlimmste Fall von allen: am Ende
hat sich der Wert nur um 1 erhöht statt um 2.
- Direkter Aufruf von incrementOptimisticUpdate: das gleiche Ergebnis
- Direkter Aufruf von incrementPessimisticUpdateExclusive: Das ist schönste Fall:
"increment" von Thread 2 wird solange blockiert, bis Thread 1 fertig ist.
- Aufruf von incrementPessimisticUpdateExclusive durch Stateful Bean: Thread 2 wird
blockiert bis Thread 1 fertig ist.
- Aufruf von incrementPessimisticUpdateExclusive durch Stateless Bean: beide Threads
laufen unbeeindruckt durch. Grund scheint zu sein, dass bereits vorher eine Bean-Methode
ohne Access Intent aufgerufen wurde (findByPrimaryKey).
Links zu IBM zu diesem Thema
Using access intent policies:
http://publib.boulder.ibm.com/infocenter/wsphelp/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/tejb_axi.html
Frequently asked questions: Access intent:
http://publib.boulder.ibm.com/infocenter/wsphelp/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/rejb_axifaq.html