Dynamischen Abfrageservice verwenden
In bestimmten Situationen im Entwicklungsprozess kann es vorteilhaft sein, den dynamischen Abfrageservice anstelle des regulären EJB-Abfrageservice (Enterprise JavaBeans) zu verwenden, der als Implementierungsabfrage bezeichnet werden kann. Beispielsweise kann der dynamische Abfrageservice in der Testphase während der Anwendungsausführung verwendet werden, so dass die Anwendung nicht erneut implementiert werden muss.
Informationen zu diesem Vorgang
- Sie müssen zur Laufzeit der Anwendung (und nicht während der Implementierung) eine Abfrage über das Programm definieren.
- Sie müssen mehrere CMP- oder CMR-Felder mit einer Abfrage zurückgeben. (In Implementierungsabfragen darf in der Klausel SELECT nur ein Element angegeben werden). Weitere Informationen finden Sie im Artikel "Beispiel: EJB-Abfragen".
- Sie möchten einen berechneten Ausdruck in der berechneten Ausdruck in der Abfrage zurückgeben.
- Sie möchten Methoden für Werteobjekte oder Bean-Methoden in der Abfrageanweisung verwenden. Weitere Informationen finden Sie im Artikel "Pfadausdrücke".
- Sie möchten eine EJB-Abfrage in der Entwicklungsphase interaktiv testen, aber die Anwendung nicht jedes Mal erneut implementieren, wenn Sie eine Finder- oder Select-Abfrage aktualisieren.
Die Verwendung der API des dynamischen Abfrageservice entspricht im Wesentlichen der Verwendung jeder anderen J2EE-EJB-Anwendungsbean. Sie ist in "com.ibm.websphere.ejbquery" im API-Paket enthalten.
ferne Schnittstelle = com.ibm.websphere.ejbquery.Query
ferne Home-Schnittstelle = com.ibm.websphere.ejbquery.QueryHome
lokale Schnittstelle = com.ibm.websphere.ejbquery.QueryLocal
lokale Home-Schnittstelle = com.ibm.websphere.ejbquery.QueryLocalHome
Eine lokale Schnittstelle bietet eine bessere EJB-Gesamtleistung als eine ferne Schnittstelle, weil es weniger Speicher des Anwendungsservers verbraucht.
Vorgehensweise
Beispiel
- Ferne Schnittstelle für dynamische Abfrage verwenden
Bei der Ausführung einer dynamischen EJB-Abfrage (Enterprise JavaBeans) über die ferne Schnittstelle wird die Methode "executeQuery" in der Schnittstelle "Query" aufgerufen. Die Methode "executeQuery" hat für diese Schnittstelle das Transaktionsattribut REQUIRED. Deshalb muss nicht explizit ein Transaktionskontext für die Abfrage erstellt werden.
Bei der Ausführung einer dynamischen EJB-Abfrage (Enterprise JavaBeans) über die ferne Schnittstelle wird die Methode "executeQuery" in der Schnittstelle "Query" aufgerufen. Die Methode "executeQuery" hat für diese Schnittstelle das Transaktionsattribut REQUIRED. Deshalb muss nicht explizit ein Transaktionskontext für die Abfrage erstellt werden.
Beginnen Sie mit den folgenden Importanweisungen:
import com.ibm.websphere.ejbquery.QueryHome; import com.ibm.websphere.ejbquery.Query; import com.ibm.websphere.ejbquery.QueryIterator; import com.ibm.websphere.ejbquery.IQueryTuple; import com.ibm.websphere.ejbquery.QueryException;
Schreiben Sie anschließend Ihre Abfrageanweisung in Form einer Zeichenfolge. Das folgende Beispiel ruft beispielsweise die Namen und EJB-Referenzen für unterbezahlte Mitarbeiter auf:
String query = "select e.name as name , object(e) as emp from EmpBean e where e.salary < 50000";
Erstellen Sie ein Query-Objekt, indem Sie eine Referenz von der Klasse QueryHome anfordern. (Diese Klasse definiert die Methode executeQuery.) Zur Vereinfachung verwendet das folgende Beispiel den JNDI-Namen für dynamische Abfragen für das Query-Objekt:
InitialContext ic = new InitialContext(); Object obj = ic.lookup("com/ibm/websphere/ejbquery/Query"); QueryHome qh = ( QueryHome) javax.rmi.PortableRemoteObject.narrow( obj, QueryHome.class ); Query qb = qh.create();
Anschließend müssen Sie die maximale Größe für die Abfrageergebnismenge festlegen, die in dem in der Klasse "QueryIterator" enthaltenen Objekt "QueryIterator" definiert ist. Anschließend müssen Sie die maximale Größe für die Abfrageergebnismenge festlegen, die in dem im API-Paket "QueryIterator" enthaltenen Objekt "QueryIterator" definiert ist. Dieses Beispiel setzt die maximale Größe für das Abfrageergebnis auf 99:
QueryIterator it = qb.executeQuery(query, null, null ,0, 99 );
Der Iterator enthält eine Sammlung von IQueryTuple-Objekten, die Datensätze der zurückgegebenen Objektgruppenwerte sind. Den Kriterien der Beispielabfrageanweisung entsprechend, enthält jedes Tupel in diesem Szenario einen Wert name und einen Wert object(e). Verwenden Sie zum Anzeigen des Inhalts des Abfrageergebnisses folgenden Code:while (it.hasNext()) { IQueryTuple tuple = (IQueryTuple) it.next(); System.out.print( it.getFieldName(1) ); String s = (String) tuple.getObject(1); System.out.println( s); System.out.println( it.getFieldName(2) ); Emp e = ( Emp) javax.rmi.PortableRemoteObject.narrow( tuple.getObject(2), Emp.class ); System.out.println( e.getPrimaryKey().toString()); }
Die Ausgabe des Programms könnte wie folgt aussehen:name Bob emp 1001 name Dave emp 298003 ...
Abschließend müssen alle Ausnahmen abgefangen und behandelt werden. Eine Ausnahme kann eintreten, wenn eine Abfrageanweisung einen Syntaxfehler enthält oder wenn zur Laufzeit ein Verarbeitungsfehler auftritt. Das folgende Beispiel fängt diese Ausnahmen ab und behandelt sie:} catch (QueryException qe) { System.out.println("Query Exception "+ qe.getMessage() ); }
Verarbeitung umfangreicher Ergebnismengen für Abfragen mit der fernen Schnittstelle
Wenn Ihre Abfrage umfangreiche Ergebnismengen zurückgegeben soll, können Sie die Abfrage so programmieren, dass die Ergebnisse in mehreren kleineren, besser verwaltbaren Einheiten zurückgegeben werden. Verwenden Sie die Parameter "skipRow" und "maxRow" der fernen Methode "executeQuery", um die Antwort in Blöcken abzurufen. Beispiel:
int skipRow=0; int maxRow=100; QueryIterator it = null; do { it = qb.executeQuery(query, null, null ,skipRow, maxRow ); while (it.hasNext()) { // Ergebnis anzeigen skipRow = skipRow + maxRow; } } while ( ! it.isComplete() ) ;
- Lokale Schnittstelle für dynamische Abfrage verwenden
Bei der Ausführung einer dynamischen EJB-Abfrage (Enterprise JavaBeans) über die lokale Schnittstelle wird die Methode "executeQuery" in der Schnittstelle "QueryLocal" aufgerufen. Diese Schnittstelle leitet keine Transaktion für die Methode ein. Deshalb müssen Sie für die Abfrage explizit einen Transaktionskontext einrichten.
Anmerkung: Zum Einrichten eines Transaktionskontextes ruft das folgende Beispiel die Methoden begin() und commit() auf. Alternativ zur Verwendung dieser Methoden können Sie Ihren Abfragecode auch einfach in eine EJB-Methode einbetten, die in einem Transaktionskontext ausgeführt wird.Beginnen Sie den Abfragecode mit den folgenden Importanweisungen:
import com.ibm.websphere.ejbquery.QueryLocalHome; import com.ibm.websphere.ejbquery.QueryLocal; import com.ibm.websphere.ejbquery.QueryLocalIterator; import com.ibm.websphere.ejbquery.IQueryTuple; import com.ibm.websphere.ejbquery.QueryException;
Schreiben Sie anschließend Ihre Abfrageanweisung in Form einer Zeichenfolge. Das folgende Beispiel ruft beispielsweise die Namen und EJB-Referenzen für unterbezahlte Mitarbeiter auf:
String query = "select e.name, object(e) from EmpBean e where e.salary < 50000 ";
Erstellen Sie ein QueryLocal-Objekt, indem Sie eine Referenz von der Klasse QueryLocalHome anfordern. (Diese Klasse definiert die Methode executeQuery.) Im folgenden Beispiel wird ejb/query als lokale EJB-Referenz verwendet, die auf den JNCI-Namen für dynamische Abfragen (com/ibm/websphere/ejbquery/Query) verweist:
InitialContext ic = new InitialContext(); QueryLocalHome qh = ( LocalQueryHome) ic.lookup( "java:comp/env/ejb/query" ); QueryLocal qb = qh.create();
Der letzte Teil des Codes leitet eine Transaktion ein, ruft die Methode executeQuery auf und zeigt die Abfrageergebnisse an. Die Klasse QueryLocalIterator wird instanziert, weil sie das Abfrageergebnis definiert. Diese Klasse ist im API-Paket der Klasse "QueryIterator" enthalten. Der Iterator verliert am Ende der Transaktion seine Gültigkeit. Sie müssen den Iterator im selben Transaktionsbereich wie den Aufruf executeQuery verwenden.
userTransaction.begin(); QueryLocalIterator it = qb.executeQuery(query, null, null); while (it.hasNext()) { IQueryTuple tuple = (IQueryTuple) it.next(); System.out.print( it.getFieldName(1) ); String s = (String) tuple.getObject(1); System.out.println( s); System.out.println( it.getFieldName(2) ); EmpLocal e = ( EmpLocal ) tuple.getObject(2); System.out.println( e.getPrimaryKey().toString()); } userTransaction.commit();
In den meisten Fällen ist das QueryLocalIterator-Objekt bedarfsgesteuert, d. h. die Daten werden inkrementell zurückgegeben. Für jeden Abruf eines Datensatzes aus der Datenbank muss die Methode next() für den Iterator aufgerufen werden. (Es gibt Situationen, in denen der Iterator nicht bedarfsgesteuert ist. Nähere Informationen hierzu finden Sie im Teilabschnitt "Lokale Abfrageschnittstellen" des Artikels Hinweise zur Leistung des dynamischen Abfrageservice.)
Da das vollständige Abfrageergebnis inkrementell im Speicher des Anwendungsservers abgelegt wird, können Sie die Größe problemlos steuern. Während eines Testlaufs können Sie beispielsweise feststellen, dass nur ein paar Tupel des Abfrageergebnisses erforderlich sind. In diesem Fall können Sie mit einem Aufruf der Methode "close()" für das Objekt "QueryLocalIterator" die Abfrageschleife schließen. Damit werden die vom Iterator verwendeten SQL-Ressourcen freigegeben. Andenfalls werden diese Ressourcen erst freigegeben, wenn sich die gesamte Ergebnisobjektgruppe im Speicher befindet oder die Transaktion endet.