Las colas de consulta permiten a las aplicaciones crear una cola calificada por una consulta en el servidor o en eXtreme Scale local para una entidad. Las entidades del resultado de la consulta se almacenan en esta cola. Actualmente, la cola de consulta sólo se admite en una correlación que utilice la estrategia de bloqueo pesimista.
Varios clientes y transacciones comparten una cola de consulta. Una vez que la cola de consulta se queda vacía, la consulta de entidad asociada con esta cola se vuelve a ejecutar y los nuevos resultados se añaden a la cola. Una cola de consulta se identifica de forma exclusiva mediante la serie de consulta de entidad y los parámetros. Sólo hay una instancia para cada cola de consulta exclusiva en una instancia de ObjectGrid. Consulte la documentación de la API EntityManager para obtener más información.
El ejemplo siguiente muestra cómo se puede utilizar la cola de consulta.
/**
* Obtener una tarea de tipo pregunta sin asignar
*/
private void getUnassignedQuestionTask() throws Exception {
EntityManager em = og.getSession().getEntityManager();
EntityTransaction tran = em.getTransaction();
QueryQueue queue = em.createQueryQueue("SELECT t FROM Task t
WHERE t.type=?1 AND t.status=?2", Task.class);
queue.setParameter(1, new Integer(Task.TYPE_QUESTION));
queue.setParameter(2, new Integer(Task.STATUS_UNASSIGNED));
tran.begin();
Task nextTask = (Task) queue.getNextEntity(10000);
System.out.println("next task is " + nextTask);
if (nextTask != null) {
assignTask(em, nextTask);
}
tran.commit();
}
El ejemplo anterior crea una cola de consulta QueryQueue con una serie de consulta de entidad, "SELECT t FROM Task t WHERE t.type=?1 AND t.status=?2". A continuación, establece los parámetros del objeto QueryQueue. Esta cola de consulta representa todas las tareas no asignadas del tipo "question" (pregunta). El objeto QueryQueue es muy parecido al objeto Query de entidad.
Una vez creado QueryQueue, se inicia una transacción de entidad y se invoca el método getNextEntity, que recupera la siguiente entidad disponible con un valor de tiempo de espera establecido en 10 segundos. Una vez recuperada la entidad, se procesa en el método assignTask. El método assignTask modifica la instancia de la entidad Task y cambia el estado a "assigned" (asignado), lo cual la elimina eficazmente de la cola, puesto que ya no coincide con el filtro de QueryQueue. Una vez asignada, la transacción se confirma.
Puede recuperar entidades en un bucle. A continuación se muestra un ejemplo que ilustra cómo obtener todas las tareas de tipo pregunta sin asignar.
/**
* Obtener todas las tareas de tipo pregunta sin asignar
*/
private void getAllUnassignedQuestionTask() throws Exception {
EntityManager em = og.getSession().getEntityManager();
EntityTransaction tran = em.getTransaction();
QueryQueue queue = em.createQueryQueue("SELECT t FROM Task t WHERE
t.type=?1 AND t.status=?2", Task.class);
queue.setParameter(1, new Integer(Task.TYPE_QUESTION));
queue.setParameter(2, new Integer(Task.STATUS_UNASSIGNED));
Task nextTask = null;
do {
tran.begin();
nextTask = (Task) queue.getNextEntity(10000);
if (nextTask != null) {
System.out.println("next task is " + nextTask);
}
tran.commit();
} while (nextTask != null);
}
Si hay 10 tareas de tipo pregunta sin asignar en la correlación de entidad, esperaría tener 10 entidades impresas en la consola. No obstante, si ejecuta este ejemplo, observará que el programa nunca sale, que es lo contrario de lo que esperaba.
Cuando se crea una cola de consulta y se llama a getNextEntity, la consulta de entidad asociada con la cola se ejecuta y en la cola se muestran 10 resultados. Al llamar a getNextEntity, una entidad se extrae de la cola. Después de ejecutar 10 llamadas a getNextEntity, la cola se queda vacía. La cola de la entidad se volverá a ejecutar automáticamente. Puesto que estas 10 entidades siguen existiendo y coinciden con el criterio del filtro de la cola de consulta, se vuelven a colocar en la cola.
Si se añade la línea siguiente después de la sentencia println(), sólo verá impresas 10 entidades.
em.remove(nextTask);
Para obtener información sobre cómo utilizar SessionHandle con QueryQueue en un despliegue de colocación por contenedor, lea la información sobre Integración de SessionHandle.
En un entorno distribuido de eXtreme Scale, una cola de consulta puede crearse para una partición o para todas las particiones. Si se crea una cola de consulta para todas las particiones, habrá una instancia de cola de consulta en cada partición.
Cuando un cliente intenta obtener la siguiente entidad mediante el método QueryQueue.getNextEntity o QueryQueue.getNextEntities, el cliente envía una solicitud a una de las particiones. Un cliente envía solicitudes PEEK y PIN al servidor.
El ejemplo siguiente muestra cómo se recupera una entidad de una cola de consulta que se despliega en todas las particiones (n):
El método para crear un objeto QueryQueue en el gestor de entidades es el siguiente:
public QueryQueue createQueryQueue(String qlString, Class entityClass);
El resultado de la cola de la consulta se debe proyectar en el objeto definido por el segundo parámetro en el método, Clase entityClass.
Si se especifica este parámetro, la clase debe tener el mismo nombre de entidad que el especificado en la serie de consulta. Esto resulta útil si desea proyectar una entidad en una entidad de subconjunto. Si se utiliza un valor nulo como clase de entidad, el resultado no se proyectará. El valor almacenado en la correlación tendrá un formato de tuple de entidad.
En un entorno distribuido de eXtreme Scale, la cola de consulta sólo se admite en correlaciones de eXtreme Scale con modalidad de bloqueo pesimista. Por lo tanto, no hay memoria caché cercana en el cliente. No obstante, un cliente podría tener datos (clave y valor) en la correlación transaccional. Esto podría desembocar potencialmente en una colisión de claves cuando una entidad recuperada del servidor comparte la misma clave que una entrada de la correlación transaccional.
La colisión de claves sólo sucede cuando hay datos en la correlación transaccional. Es decir, sólo tiene lugar cuando se llama a getNextEntity o getNextEntities en una transacción que ya estaba sucia (se han insertado datos nuevos o se han actualizado datos). Si una aplicación prefiere que no se produzcan colisiones de claves, debe llamar siempre a getNextEntity o getNextEntities en una transacción que no se haya ensuciado.
En el primer caso, el servidor descubre que el cliente va a concluir cuando intenta responder al cliente. En el segundo caso, cuando el cliente obtiene una o más entidades del servidor, se coloca un bloqueo X en estas entidades. Si el cliente concluye, la transacción excederá el tiempo de espera y se liberará el bloqueo X.
Por norma, las colas de consulta no reconocen la cláusula ORDER BY. Si llama a getNextEntity o getNextEntities en la cola de consulta, no se garantiza que las entidades se devuelvan en función del orden. La razón es que las entidades no se pueden ordenar en las particiones. En el caso de que la cola de consulta se despliegue en todas las particiones, cuando se ejecuta una llamada getNextEntity o getNextEntities, se elige una partición aleatoria para procesar la solicitud. Por lo tanto, no se garantiza el orden.
ORDER BY se reconoce si se despliega una cola de consulta en una sola partición.
Si desea más información consulte API EntityManager Query.
Cada llamada a QueryQueue.getNextEntity o QueryQueue.getNextEntities recupera las entidades coincidentes de una partición aleatoria. Las aplicaciones deben llamar exactamente a una QueryQueue.getNextEntity o QueryQueue.getNextEntities en una transacción. De lo contrario, eXtreme Scale podría finalizar afectando a entidades de varias particiones, que provoca que se genere una excepción durante la confirmación.