MQSeries Functions se puede utilizar en una amplia variedad de escenarios. En esta sección se revisan algunos de los escenarios más comunes, que incluyen Gestión básica de mensajes, Conectividad de aplicaciones y Publicación de datos.
La forma más básica de gestión de mensajes con MQSeries DB2 Functions se produce cuando todas las aplicaciones de bases de datos se conectan al mismo servidor de DB2. Los clientes pueden ser locales al servidor de bases de datos o pueden estar distribuidos en un entorno de red.
En un escenario sencillo, el Cliente A invoca la función MQSEND para enviar una serie definida por el usuario a la ubicación de servicio por omisión. Luego las funciones de MQSeries se ejecutan dentro de DB2 en el servidor de bases de datos. Luego, el Cliente B invoca la función MQRECEIVE para eliminar el mensaje que hay al principio de la cola definida por el servicio por omisión y devolverlo al cliente. De nuevo, DB2 ejecuta las funciones de MQSeries que realizan esta tarea.
Los clientes de bases de datos pueden utilizar la gestión sencilla de mensajes de varias formas. Algunas aplicaciones comunes de la gestión de mensajes son:
El siguiente escenario amplía el escenario sencillo descrito anteriormente para incorporar la gestión remota de mensajes. Es decir, se envía un mensaje entre la Máquina A y la Máquina B. La secuencia de pasos es la siguiente:
Mediante MQSEND, un programador o usuario de DB2 elige los datos que desea enviar y dónde los desea enviar y se enviarán. En la industria esto se suele denominar "Enviar y olvidarse", que significa que el remitente se limita a enviar un mensaje, confiando en los protocolos de distribución garantizados de MQSeries para asegurar que el mensaje alcanza su destino. Los siguientes ejemplos lo ilustran.
Ejemplo 4: Para enviar una serie definida por el usuario al punto de servicio myPlace con la política highPriority:
VALUES DB2MQ.MQSEND('myplace','highPriority','test')
Aquí, la política highPriority hace referencia a una política definida en el Repositorio de AMI que establece la prioridad de MQSeries como la de más alto nivel y quizás ajuste otras calidades de servicio, como permanencia.
El contenido del mensaje puede estar compuesto por cualquier combinación válida de datos específicos de usuario y SQL. Esto incluye funciones anidadas, operadores y conversiones. Por ejemplo, dada una tabla EMPLOYEE, con las columnas VARCHAR LASTNAME, FIRSTNAME y DEPARTMENT, para enviar un mensaje que contenga esta información a cada empleado de DEPARTMENT 5LGA debería hacer lo siguiente:
Ejemplo 5:
SELECT DB2MQ.MQSEND(LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT) FROM EMPLOYEE WHERE DEPARTMENT = '5LGA'
Si esta tabla también tuviera una columna AGE de enteros, se incluiría del siguiente modo:
Ejemplo 6:
SELECT DB2MQ.MQSEND (LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT|| ' ' || char(AGE)) FROM EMPLOYEE WHERE DEPARTMENT = '5LGA'
Si la tabla EMPLOYEE tuviera una columna RESUME de tipo CLOB en lugar de una columna AGE, se podría enviar un mensaje que contuviera la información correspondiente a cada empleado del DEPARTMENT 5LGA, del modo siguiente:
Ejemplo 7:
SELECT DB2MQ.MQSEND (clob(LASTNAME) || ' ' || clob(FIRSTNAME) || ' ' || clob(DEPARTMENT) || ' ' || RESUME)) FROM EMPLOYEE WHERE DEPARTMENT = '5LGA'
Ejemplo 8:
Finalmente, el siguiente ejemplo muestra cómo el contenido del mensaje se puede obtener mediante cualquier expresión de SQL válida. Dada una segunda tabla, DEPT, que contiene las columnas VARCHAR DEPT_NO y DEPT_NAME, se pueden enviar mensajes que contengan LASTNAME y DEPT_NAME de los empleados:
Ejemplo 8:
SELECT DB2MQ.MQSEND(e.LASTNAME || ' ' || d.DEPTNAME) FROM EMPLOYEE e, DEPT d WHERE e.DEPARTMENT = d.DEPTNAME
MQSeries DB2 Functions permite recibir o leer mensajes. La diferencia entre leer y recibir es que al leer se devuelve el mensaje al principio de una cola sin eliminarlo de la misma, mientras que la operación de recibirlo hace que el mensaje se elimine de la cola. Un mensaje recuperado mediante una operación de recepción sólo se puede recuperar una vez, mientras que un mensaje recuperado mediante una operación de lectura permite recuperar el mismo mensaje varias veces. Los siguientes ejemplos lo demuestran:
Ejemplo 8:
VALUES DB2MQ.MQREAD()
Este ejemplo devuelve una serie VARCHAR que contiene el mensaje que hay al principio de la cola definida por el servicio por omisión utilizando la política de calidad de servicio por omisión. Es importante observar que si no hay ningún mensaje disponible para su lectura, se devuelve un valor nulo. Esta operación no modifica la cola.
Ejemplo 9:
VALUES DB2MQ.MQRECEIVE('Employee_Changes')
El ejemplo anterior muestra cómo se puede eliminar un mensaje del principio de la cola definida por el servicio Employee_Changes utilizando la política por omisión.
Una característica muy potente de DB2 es la posibilidad de generar una tabla a partir de una función definida por el usuario (o suministrada por DB2). Puede aprovechar esta característica de función de tablas para permitir que el contenido de una cola se materialice como una tabla de DB2. El ejemplo siguiente muestra la forma más sencilla de esta función:
Ejemplo 10:
SELECT t.* FROM table ( DB2MQ.MQREADALL()) t
Esa consulta devuelve una tabla que consta de todos los mensajes de la cola definida por el servicio por omisión y los metadatos sobre estos mensajes. Aunque la definición completa de la estructura de la tabla devuelta se define en el Apéndice, la primera columna refleja el contenido del mensaje y las demás columnas contienen los metadatos. Para devolver únicamente los mensajes, se podría reescribir el ejemplo:
Ejemplo 11:
SELECT t.MSG FROM table (DB2MQ.MQREADALL()) t
La tabla que devuelve una función de tabla no difiere de una tabla recuperada directamente de la base de datos. Esto significa que puede utilizar esta tabla de varias formas. Por ejemplo, puede unir el contenido de la tabla con otra tabla o contar el número de mensajes de una cola:
Ejemplo 12:
SELECT t.MSG, e.LASTNAME FROM table (DB2MQ.MQREADALL() ) t, EMPLOYEE e WHERE t.MSG = e.LASTNAME
Ejemplo 13:
SELECT COUNT(*) FROM table (DB2MQ.MQREADALL()) t
También puede ocultar el hecho de que la fuente de la tabla es una consulta, creando una vista sobre una función de tabla. Por ejemplo, el siguiente ejemplo crea una vista denominada NEW_EMP sobre la cola a la que hace referencia el servicio denominado NEW_EMPLOYEES:
Ejemplo 14:
CREATE VIEW NEW_EMP (msg) AS SELECT t.msg FROM table (DB2MQ.MQREADALL()) t
En este caso, la vista se define con una sola columna que contiene un mensaje entero. Si los mensajes tienen una estructura simple, por ejemplo contienen dos campos de longitud fija, es más sencillo utilizar las funciones incorporadas de DB2 para analizar el mensaje en las dos columnas. Por ejemplo, si sabe que los mensajes que se envían a una determinada cola siempre contienen un apellido de 18 caracteres seguido de un nombre de 18 caracteres, puede definir una vista que contenga cada campo como una columna separada, del siguiente modo:
Ejemplo 15:
CREATE VIEW NEW_EMP2 AS SELECT left(t.msg,18) AS LNAME, right(t.msg,18) AS FNAME FROM table(DB2MQ.MQREADALL()) t
Una nueva característica de DB2 Stored Procedure Builder, MQSeries Assist Wizard, permite crear nuevas funciones y vistas de tablas de DB2 que correlacionarán estructuras delimitadas de mensajes con columnas.
Finalmente, suele resultar útil almacenar el contenido de uno o más mensajes en la base de datos. Esto se puede conseguir utilizando toda la potencia de SQL para manipular y almacenar contenido de mensajes. Quizás el ejemplo más sencillo es el siguiente:
Ejemplo 16:
INSERT INTO MESSAGES SELECT t.msg FROM table (DB2MQ.MQRECEIVEALL()) t
Dada una tabla MESSAGES, con una sola columna de VARCHAR(2000), la sentencia anterior insertará los mensajes de la cola del servicio por omisión en la tabla. Esta técnica se puede mejorar para cubrir una amplia variedad de circunstancias.
La integración de aplicaciones es un elemento común de muchas soluciones. Tanto si se integra una aplicación adquirida en una infraestructura existente como si se integra una aplicación recientemente desarrollada en un entorno existente, generalmente nos enfrentamos a la tarea de combinar un grupo heterogéneo de subsistemas para que funcionen conjuntamente. MQSeries se suele considerar la herramienta esencial para integrar aplicaciones. MQSeries, al que se puede acceder desde la mayoría de entornos de hardware, software y lenguajes, ofrece los métodos para interconectar un grupo muy heterogéneo de aplicaciones.
Esta sección trata algunos escenarios de integración de aplicaciones y cómo se pueden utilizar con DB2. Puesto que el tema es muy amplio, el tratamiento de la integración de aplicaciones queda fuera del ámbito de este manual. Por lo tanto, nos centraremos en dos temas sencillos: las comunicaciones tipo petición y respuesta y MQSeries Integrator y publicación y suscripción.
El método de comunicaciones de petición y respuesta (R/R) es una técnica muy común para que una aplicación solicite los servicios de otra. Un modo de hacerlo es que el peticionario envíe un mensaje al proveedor de servicio solicitando que realice un trabajo. Una vez realizado el trabajo, el proveedor puede decidir enviar los resultados (o simplemente una confirmación de que se ha realizado el trabajo) al peticionario. Pero utilizando las técnicas básicas de gestión de mensajes descritas anteriormente, no hay nada que conecte la petición del remitente con la respuesta del proveedor de servicio. A no ser que el peticionario espere una respuesta antes de continuar, se deben utilizar algunos mecanismos para asociar cada respuesta con su petición. En lugar de imponer que el programador cree dicho mecanismo, MQSeries ofrece un identificador de correlación que permite la correlación de mensajes en un intercambio.
Aunque este mecanismo se puede utilizar de varias formas, el modo más sencillo consiste en que el peticionario marque un mensaje con un identificador de correlación conocido utilizando, por ejemplo, la siguiente sentencia:
Ejemplo 17:
DB2MQ.MQSEND ('myRequester','myPolicy','SendStatus:cust1','Req1')
Esta sentencia añade un parámetro final, Req1, a la anterior sentencia MQSEND para indicar el identificador de correlación correspondiente a la petición.
Para recibir una respuesta a esta petición específica, utilice la sentencia MQRECREIVE correspondiente para recuperar de forma selectiva el primer mensaje definido por el servicio indicado que coincida con este identificador de correlación, del modo siguiente:
Ejemplo 18:
DB2MQ.MQRECEIVE('myReceiver','myPolicy','Req1')
Si la aplicación que da servicio a la petición está ocupada y el peticionario emite el mandato MQRECEIVE anterior antes de que se envíe la respuesta, no se encontrará ningún mensaje que coincida con este identificador de correlación.
Para recibir la petición de servicio y el identificador de correlación, se utiliza una sentencia como la siguiente:
Ejemplo 19:
SELECT msg, correlid FROM table (DB2MQ.MQRECEIVEALL('aServiceProvider','myPolicy',1)) t
Esto devuelve el mensaje y el identificador de correlación de la primera petición del servicio aServiceProvider.
Una vez realizado el servicio, envía el mensaje de respuesta a la cola descrita por aRequester. Mientras tanto, el peticionario del servicio puede estar realizando otro trabajo. De hecho, no hay garantía de que la petición inicial de servicio se responda dentro de un periodo de tiempo definido. El programador debe gestionar los tiempos de espera a nivel de aplicación como este; el peticionario debe sondear para detectar la presencia de la respuesta.
La ventaja de este proceso asíncrono que no depende del tiempo es que el peticionario y el proveedor de servicio se ejecutan de forma completamente independiente. Esto se puede utilizar para adaptar entornos en los que las aplicaciones sólo se conectan de forma intermitente y entornos con procesos por lotes en los que se agregan varias peticiones o respuestas antes del proceso. Este tipo de agregación se suele utilizar en entornos de almacén de datos para actualizar periódicamente un almacén de datos o almacén de datos operativos.
Otro escenario común en la integración de aplicaciones es que una aplicación notifique a otras aplicaciones sobre sucesos de interés. Esto se puede realizar fácilmente enviando un mensaje a una cola supervisada por otra aplicación. El contenido del mensaje puede ser una serie definida por el usuario o puede estar compuesto a partir de columnas de bases de datos. Normalmente, con la función MQSEND se envían mensajes sencillos. Cuando estos mensajes se tienen que enviar simultáneamente a varios receptores, se puede utilizar el recurso de Lista de distribución de la AMI de MQSeries.
Una lista de distribución se define mediante la herramienta de administración de AMI. Una lista de distribución comprende una lista de servicios individuales. Se envía un mensaje enviado a una lista de distribución a cada uno de los servicios definidos dentro de la lista. Esto resulta especialmente útil cuando se sabe que unos cuantos servicios están siempre interesados en cada mensaje. El ejemplo siguiente muestra el envío de un mensaje a la lista de distribución interestedParties:
Ejemplo 20:
DB2MQ.MQSEND('interestedParties','información de interés general');
Cuando se necesita más control sobre los mensajes que deben recibir determinados servicios, se necesita la función de publicación y suscripción. Los sistemas de publicación y suscripción normalmente ofrecen un entorno seguro y escalable en el que varios suscriptores se pueden registrar para recibir mensajes procedentes de varios publicadores. Para dar soporte a esta función se puede utilizar la interfaz MQPublish junto con MQSeries Integrator o el recurso de publicación y suscripción de MQSeries.
MQPublish permite a los usuarios especificar opcionalmente un tema que se asociará con un mensaje. Los temas permiten a un suscriptor especificar de forma más clara los mensajes que desea aceptar. La secuencia de pasos es la siguiente:
Para publicar estos datos utilizando todos los valores por omisión y tema nulo, utilizaría la siguiente sentencia:
Ejemplo 21:
SELECT DB2MQ.MQPUBLISH (LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT|| ' ' ||char(AGE)) FROM EMPLOYEE WHERE DEPARTMENT = '5LGA'
Si se especifican por completo todos los parámetros y se simplifica el mensaje para que sólo contenga LASTNAME, la sentencia sería la siguiente:
Ejemplo 22:
SELECT DB2MQ.MQPUBLISH('HR_INFO_PUB', 'SPECIAL_POLICY', LASTNAME, 'ALL_EMP:5LGA', 'MANAGER') FROM EMPLOYEE WHERE DEPARTMENT = '5LGA'
Esta sentencia publica mensajes en el servicio de publicación HR_INFO_PUB utilizando el servicio SPECIAL_POLICY. Los mensajes indican que el remitente es el tema MANAGER. La serie del tema muestra que se pueden especificar varios temas, concatenados mediante el signo ':'. En este ejemplo, el hecho de utilizar dos temas permite a los suscriptores registrarse para ALL_EMP o sólo 5LGA para recibir estos mensajes.
Para recibir mensajes publicados, primero debe registrar su interés en los mensajes que contienen un determinado tema e indicar el nombre del servicio de suscriptor al que se deben enviar los mensajes. Es importante observar que un servicio de suscriptor AMI define un servicio intermediario y un servicio de recepción. El servicio intermediario es el modo en que el suscriptor se comunica con el intermediario de publicación y suscripción y el servicio de recepción es el lugar en el que se envían los mensajes que coinciden con la petición de suscripción. La siguiente sentencia registra un interés en el tema ALL_EMP.
Ejemplo 23:
DB2MQ.MQSUBSCRIBE('aSubscriber', 'ALL_EMP')
Una vez suscrita una aplicación, los mensajes publicados con el tema ALL_EMP se enviarán al servicio de recepción definido por el servicio de suscripción. Una aplicación puede tener varias suscripciones simultáneas. Para obtener los mensajes que coinciden con su suscripción, puede utilizar cualquiera de las funciones estándares de recuperación de mensajes. Por ejemplo, si el servicio de suscripción aSubscriber define que el servicio de recepción sea aSubscriberReceiver, la siguiente sentencia leerá de forma no destructiva el primer mensaje:
Ejemplo 24:
DB2MQ.MQREAD('aSubscriberReceiver')
Para determinar los mensajes y los temas bajo los que se han publicado, debe utilizar una de las funciones de tabla. La sentencia siguiente recibe los cinco primeros mensajes de aSubscriberReceiver y muestran el mensaje y el tema:
Ejemplo 25:
SELECT t.msg, t.topic FROM table (DB2MQ.MQRECEIVEALL('aSubscriberReceiver',5)) t
Para leer todos los mensajes con el tema ALL_EMP, puede aprovechar la potencia de SQL para emitir:
Ejemplo 26:
SELECT t.msg FROM table (DB2MQ.MQREADALL('aSubscriberReceiver')) t WHERE t.topic = 'ALL_EMP'
Cuando deja de estar interesado en suscribirse a un determinado tema, debe anular de forma explícita la suscripción mediante una sentencia como la siguiente:
Ejemplo 27:
DB2MQ.MQUNSUBSCRIBE('aSubscriber', 'ALL_EMP')
Una vez emitida esta sentencia, el intermediario de publicación y suscripción dejará de distribuir mensajes que coincidan con esta suscripción.
Otra técnica importante en la gestión de mensajes de bases de datos es la publicación automática. Utilizando un recurso de desencadenante de DB2, puede publicar mensajes automáticamente como parte de una invocación del desencadenante. Aunque existen otras técnicas para la publicación automática de datos, el enfoque basado en desencadenantes ofrece a los administradores o programadores una gran libertad para construir contenido de mensajes y flexibilidad para definir las acciones desencadenadoras. Al igual que en cualquier uso que se haga de los desencadenantes, se debe prestar atención a la frecuencia y coste de la ejecución. Los siguientes ejemplos muestran cómo se pueden utilizar desencadenantes con MQSeries DB2 Functions.
El ejemplo siguiente muestra lo fácil que resulta publicar un mensaje cada vez que se contrata un nuevo empleado. Cualquier usuario o aplicación suscritos al servicio HR_INFO_PUB con interés registrado en NEW_EMP recibirán un mensaje con la fecha, nombre y departamento de cada nuevo empleado.
Ejemplo 28:
CREATE TRIGGER new_employee AFTER INSERT ON employee REFERENCING NEW AS n FOR EACH ROW MODE DB2SQL VALUES DB2MQ.MQPUBLISH('HR_INFO_PUB&', 'NEW_EMP', current date || ' ' || LASTNAME || ' ' || DEPARTMENT)