Utilización del servicio de consulta dinámica
Hay momentos en el proceso de desarrollo en que quizá prefiera utilizar el servicio de consulta dinámica en lugar del servicio de consultas de Enterprise JavaBeans (EJB) normal (al que puede denominar consulta de despliegue). Por ejemplo, durante las pruebas el servicio de consulta dinámica puede utilizar en el tiempo de ejecución de la aplicación, de modo que no tenga que volver a desplegar la aplicación.
Acerca de esta tarea
- Es necesario definir mediante programación una consulta en tiempo de ejecución de la aplicación, en lugar de hacerlo durante el despliegue.
- Es necesario devolver varios campos CMP o CMR desde una consulta (las consultas de despliegue sólo permiten que en la cláusula SELECT se especifique un único elemento). Si desea más información, consulte el tema Ejemplo: consultas EJB.
- Si quiere devolver una expresión calculada en la consulta
- Si quiere utilizar métodos de objetos de valor o métodos bean en sentencias de consulta. Si desea más información, consulte el tema sobre las expresiones path.
- Si quiere probar de forma interactiva una consulta EJB durante el despliegue, pero no quiere desplegar la aplicación repetidamente cada vez que actualiza una consulta de búsqueda o selección (finder o select).
El uso de la API de consulta dinámica es un bean de sesión sin estado parecido al uso de cualquier otro bean de aplicación EJB de J2EE. Se incluye en com.ibm.websphere.ejbquery en el paquete de la API.
remote interface = com.ibm.websphere.ejbquery.Query
remote home interface = com.ibm.websphere.ejbquery.QueryHome
local interface = com.ibm.websphere.ejbquery.QueryLocal
local home interface = com.ibm.websphere.ejbquery.QueryLocalHome
Dado que utiliza menos memoria del servidor de aplicaciones, la interfaz local asegura un rendimiento global EJB mejor que la interfaz remota.
Procedimiento
Ejemplo
- Utilización de la interfaz remota para la consulta dinámica.
Al ejecutar una consulta dinámica EJB (Enterprise JavaBeans) mediante la interfaz remota, se llama al método executeQuery de la interfaz Query. El método executeQuery tiene un atributo de transacción de REQUIRED para esta interfaz; por tanto, no es necesario establecer explícitamente un contexto de transacción para poder ejecutar la consulta.
Al ejecutar una consulta dinámica EJB (Enterprise JavaBeans) mediante la interfaz remota, se llama al método executeQuery de la interfaz Query. El método executeQuery tiene un atributo de transacción de REQUIRED para esta interfaz; por tanto, no es necesario establecer explícitamente un contexto de transacción para poder ejecutar la consulta.
Empiece con las sentencias de importación siguientes:
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;
A continuación, escriba la sentencia de consulta como una serie, como en el ejemplo siguiente que recupera los nombres y las referencias EJB para empleados con un sueldo bajo:
String query = "select e.name as name , object(e) as emp from EmpBean e where e.salary < 50000";
Cree un objeto Query obteniendo una referencia de la clase QueryHome (esta clase define el método executeQuery method). Tenga en cuenta que por motivos de simplicidad, en el ejemplo siguiente se utiliza el nombre JNDI de la consulta dinámica para el objeto Query:
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();
A continuación, especifique un tamaño máximo para el conjunto de resultados de la consulta, que se define en el objeto QueryIterator. A continuación, debe especificar un tamaño máximo para el conjunto de resultados de la consulta, que se define en el objeto QueryIterator que se incluye en el paquete de la API QueryIterator. Este ejemplo establece el tamaño máximo del conjunto de resultados en 99:
QueryIterator it = qb.executeQuery(query, null, null ,0, 99 );
El iterador contiene una colección de objetos IQueryTuple, que son registros de los valores de recopilación devueltos Según los criterios de la sentencia de consulta del ejemplo, cada tupla de este caso práctico contiene un valor name y un valor object(e). Para visualizar el contenido del resultado de esta consulta, utilice el código siguiente: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()); }
La salida del programa puede ser similar a la siguiente:name Bob emp 1001 name Dave emp 298003 ...
Finalmente, capture y procese las excepciones. Es posible que se genere una excepción si se produce un error de sintaxis en la sentencia de la consulta o un error de proceso durante la ejecución. El ejemplo siguiente captura y procesa estas excepciones:} catch (QueryException qe) { System.out.println("Query Exception "+ qe.getMessage() ); }
Manejo de colecciones de resultados de gran tamaño para la consulta de interfaz remota
Si quiere que la consulta devuelva una gran recopilación de resultados, tiene la opción de programarla para que devuelva resultados en múltiplos más pequeños, en cantidades más manejables. Utilice los parámetros skipRow y maxRow en el método remoto executeQuery para recuperar la respuesta en chunks. Por ejemplo:
int skipRow=0; int maxRow=100; QueryIterator it = null; do { it = qb.executeQuery(query, null, null ,skipRow, maxRow ); while (it.hasNext() ) { // display result skipRow = skipRow + maxRow; } } while ( ! it.isComplete() ) ;
- Utilización de la interfaz local para la consulta dinámica.
Al ejecutar una consulta dinámica EJB (Enterprise JavaBeans) mediante la interfaz local, se llama al método executeQuery de la interfaz QueryLocal. Esta interfaz no inicia una transacción para el método; por tanto, debe establecer explícitamente un contexto de transacción para poder ejecutar la consulta.
Nota: Para establecer un contexto de transacción, el ejemplo siguiente llama a los métodos begin() y commit(). Como alternativa a la utilización de estos métodos, puede incorporar el código de consulta en un método EJB que se ejecute en un contexto de transacción.Inicie el código de consulta con las sentencias de importación siguientes:
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;
A continuación, escriba la sentencia de consulta como una serie, como en el ejemplo siguiente que recupera los nombres y las referencias EJB para empleados con un sueldo bajo:
String query = "select e.name, object(e) from EmpBean e where e.salary < 50000 ";
Cree un objeto QueryLocal obteniendo una referencia de la clase QueryLocalHome (esta clase define el método executeQuery method). Tenga en cuenta que en el ejemplo siguiente, ejb/query se utiliza como referencia local EJB que apunta al nombre JNDI de la consulta dinámica (com/ibm/websphere/ejbquery/Query):
InitialContext ic = new InitialContext(); QueryLocalHome qh = ( LocalQueryHome) ic.lookup( "java:comp/env/ejb/query" ); QueryLocal qb = qh.create();
La última porción de código inicia una transacción, llama al método executeQuery y visualiza los resultados de la consulta. Se crea una instancia de la clase QueryLocalIterator porque define el conjunto de resultados de la consulta Esta clase se incluye en el paquete de la API en la clase QueryIterator. Recuerde que el iterador pierde validez al final de la transacción; debe utilizar el iterador en el mismo ámbito de transacción que la llamada executeQuery.
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();
En la mayoría de las situaciones, el objeto QueryLocalIterator es gestionado por demanda. Es decir, provoca que los datos se devuelvan en incrementos: para cada recuperación de registro de la base de datos, debe llamarse al método next() en el iterador (pueden existir situaciones en las que el iterador no sea gestionado por demanda. Si desea más información, consulte la subsección Interfaces de consulta local del tema Consideraciones de rendimiento de consulta dinámica.)
Dado que la totalidad del conjunto de resultados de la consulta se materializa en incrementos en la memoria del servidor de aplicaciones, puede controlar su tamaño fácilmente. Durante una ejecución de prueba, por ejemplo, puede decidir que sólo se devuelvan unas cuantas tuplas del conjunto de resultados si es necesario. En ese caso, debe utilizar una llamada del método close() en el objeto QueryLocalIterator para cerrar el bucle de la consulta. De este modo se liberan recursos SQL utilizados por el iterador. De lo contrario, estos recursos no se liberan hasta que la totalidad del conjunto de resultados se acumula en la memoria o cuando termina la transacción.