|Функции MQSeries можно использовать в ряде разнообразных сценариев. |В этом разделе будет дан обзор некоторых наиболее общих сценариев, включая |базовую передачу сообщений, подключение прикладных программ и публикацию |данных.
|Базовый вариант передачи сообщений с использованием функций DB2 MQSeries |имеет место, когда все программы базы данных соединяются с одним сервером |DB2. Клиенты могут быть локальными по отношению к серверу баз данных |или распределенными в сетевой среде.
|В простом сценарии Клиент A вызывает функцию MQSEND, чтобы отправить |пользовательскую строку в местонахождение службы по умолчанию. Затем |функции MQSeries выполняются в DB2 на сервере баз данных. Через |некоторое время Клиент B вызывает функцию MQRECEIVE, чтобы принять сообщение, |стоящее первым в очереди, заданной службой по умолчанию, и возвратить его |клиенту. Для выполнения этой задачи DB2 снова вызывает функции |MQSeries.
|Клиенты баз данных могут пользоваться простой передачей сообщений рядом |способов. Наиболее обычные варианты применения передачи |сообщений: |
|Следующий сценарий по сравнению с простым сценарием, описанным выше, |дополнен удаленной передачей сообщений. Сообщение передается между |компьютером A и компьютером B. Последовательность шагов |следующая: |
|С помощью MQSEND пользователь или разработчик прикладных программ DB2 |выбирает, какие данные отправить, куда их отправить и когда они будут |отправлены. Такая ситуация обычно называется "отправить и забыть", то |есть отправитель просто посылает сообщение, полагаясь на гарантированные |протоколы доставки MQSeries, обеспечивающие, что сообщение достигнет своего |назначения. Это показано в следующих примерах.
|Пример 4: Чтобы отправить пользовательскую строку в точку службы |myPlace с правилами highPriority, введите:
|VALUES DB2MQ.MQSEND('myplace','highPriority','проверка')
|Здесь highPriority - это правила, определенные в Репозитории AMI, которые |задают для приоритета самый высокий уровень, а также могут настроить и другие |опции качества обслуживания, например, срок действия.
|В состав сообщения может входить любая разрешенная комбинация SQL и |пользовательских данных. Сюда входят вложенные функции, операторы и |преобразования типов. Например, если у нас есть таблица EMPLOYEE со |столбцами LASTNAME, FIRSTNAME и DEPARTMENT типа VARCHAR, чтобы отправить |сообщение, содержащее эту информацию для каждого сотрудника отдела 5LGA, нужно |ввести:
|Пример 5:
|SELECT DB2MQ.MQSEND(LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT) | FROM EMPLOYEE | WHERE DEPARTMENT = '5LGA'
|Если в таблице присутствует также целочисленный столбец AGE, его можно |включить так:
|Пример 6:
|SELECT DB2MQ.MQSEND | (LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT|| ' ' || char(AGE)) | FROM EMPLOYEE | WHERE DEPARTMENT = '5LGA'
|Если в таблице EMPLOYEE вместо столбца AGE есть столбец RESUME типа CLOB, |сообщение с информацией о каждом сотруднике DEPARTMENT 5LGA можно послать |так:
|Пример 7:
|SELECT DB2MQ.MQSEND | (clob(LASTNAME) || ' ' || clob(FIRSTNAME) || ' ' || clob(DEPARTMENT) || ' ' || RESUME)) | FROM EMPLOYEE | WHERE DEPARTMENT = '5LGA'
|Пример 8:
|И наконец, в следующем примере показано, как можно создать содержимое |сообщения с использованием допустимого выражения SQL. Взяв вторую |таблицу DEPT со столбцами типа VARCHAR DEPT_NO и DEPT_NAME, можно отправить |сообщение, содержащее столбцы LASTNAME и DEPT_NAME:
|Пример 8:
|SELECT DB2MQ.MQSEND(e.LASTNAME || ' ' || d.DEPTNAME) FROM EMPLOYEE e, DEPT d | WHERE e.DEPARTMENT = d.DEPTNAME
|Функции DB2 MQSeries позволяют либо получать, либо читать сообщения. |Чтение отличается от приема сообщения тем, что чтение возвращает головное |сообщение без удалении его из данной очереди, а при приеме сообщение удаляется |из очереди. С использованием операции приема сообщение можно получить |только один раз, а операция чтения позволяет получать одно и то же сообщение |многократно. Это показано в дальнейших примерах:
|Пример 8:
|VALUES DB2MQ.MQREAD()
|Этот пример возвращает строку VARCHAR, содержащую первое сообщение из |очереди, определенной службой по умолчанию с использованием правил качества |обслуживания по умолчанию. Важно отметить, что если сообщения, |доступные для чтения, отсутствуют, будет возвращено пустое значение. |При этой операции очередь не изменяется.
|Пример 9:
|VALUES DB2MQ.MQRECEIVE('Employee_Changes')
|В этом примере показано, как сообщение можно удалить из начала очереди, |заданной службой Employee_Changes, с использованием правил по |умолчанию.
|Полезная особенность DB2 - возможность сгенерировать таблицу при помощи |пользовательской функции (или функции, предоставляемой DB2). Эту |особенность табличных функций можно использовать, чтобы разрешить использовать |содержимое очереди как таблицу DB2. Простейший случай показан на |следующем примере:
|Пример 10:
|SELECT t.* FROM table ( DB2MQ.MQREADALL()) t
|Это требование возвращает таблицу, включающую в себя все сообщения в |очереди, определенной службой по умолчанию, и метаданные об этих |сообщениях. Полное описание возвращенной структуры таблицы приведено в |Приложении, отметим лишь, что первый столбец отражает содержимое сообщения, а |остальные столбцы содержат метаданные. Чтобы требование возвращало |только сообщения, этот пример можно изменить так:
|Пример 11:
|SELECT t.MSG FROM table (DB2MQ.MQREADALL()) t
|Таблица, возвращенная табличной функцией, не отличается от таблицы, |полученной из базы данных непосредственно. Это значит, что эту таблицу |можно использовать в самых разных целях. Например, можно объединить |содержимое этой таблицы с другой таблицей или подсчитать число сообщений в |очереди:
|Пример 12:
|SELECT t.MSG, e.LASTNAME | FROM table (DB2MQ.MQREADALL() ) t, EMPLOYEE e | WHERE t.MSG = e.LASTNAME
|Пример 13:
|SELECT COUNT(*) FROM table (DB2MQ.MQREADALL()) t
|Кроме того, можно скрыть факт, что источником таблицы является очередь, |если создать производную таблицу от табличной функции. Например, в |следующем примере на основании очереди, к которой служба обращается по имени |NEW_EMPLOYEES, создается производная таблица NEW_EMP:
|Пример 14:
|CREATE VIEW NEW_EMP (msg) AS | SELECT t.msg FROM table (DB2MQ.MQREADALL()) t
|Здесь производная таблица определяется только с одним столбцом, в котором |содержится все сообщение. Если структура сообщения простая, для |примера, содержащего два поля фиксированной длины, можно напрямую |воспользоваться встроенными функциями DB2, чтобы разбить данное сообщение на |два столбца. Например, если известно, что сообщения, отправляемые в |конкретную очередь, всегда содержат фамилию длиной не более 18 символов, за |которой следует максимум 18-символьное имя, вы можете опередить производную |таблицу, содержащую каждое поле как отдельный столбец, так:
|Пример 15:
|CREATE VIEW NEW_EMP2 AS | SELECT left(t.msg,18) AS LNAME, right(t.msg,18) AS FNAME | FROM table(DB2MQ.MQREADALL()) t
|Для создания новых табличных функций и производных таблиц DB2, которые |будут отображать в столбцы структуру сообщений с ограничителями можно |использовать новую возможность Построителя хранимых процедур DB2 - мастер |поддержки MQSeries.
|И наконец, как правило, полезно хранить содержимое одного или нескольких |сообщений в базе данных. Для этого можно использовать все возможности |SQL по управлению и хранению содержимого сообщений. Приведем простейший |пример:
|Пример 16:
|INSERT INTO MESSAGES | SELECT t.msg FROM table (DB2MQ.MQRECEIVEALL()) t
|Этот оператор будет вставлять в таблицу MESSAGES, содержащую единственный |столбец VARCHAR(2000), сообщения из очереди службы по умолчанию. |Развивая эту технику, можно охватить широкий спектр самых разнообразных |обстоятельств.
|Интеграция программ - обычный элемент во многих решениях. Будь то |интеграция приобретенной программы в существующую инфраструктуру или всего |лишь интеграция только что разработанной программы в существующую среду, мы |часто сталкиваемся с задачей склеить вместе разнородное собрание подсистем, |чтобы сформировать работающее целое. MQSeries обычно рассматривается |как необходимый инструмент для интеграции программ. Доступная на |большей части аппаратных средств, программного обеспечения и языковых сред, |MQSeries обеспечивает средства для связи воедино самого разнородного собрания |программ.
|В этом разделе мы обсудим некоторые сценарии интеграции программ и |возможности их использования с DB2. Поскольку тема весьма широка, |всестороннее обсуждение интеграции программ выходит за рамки этой |работы. Поэтому остановимся на двух простых вопросах: |взаимодействие требование/ответ, а также интегратор MQSeries и |публикация/подписка.
|Метод взаимодействия требование/ответ (R/R) - наиболее общая техника, когда |одна программа запрашивает службы другой программы. В одном из таких |способов реквестер отправляет сообщение провайдеру службы, требуя, чтобы была |выполнена некоторая работа. Как только работа выполнена, провайдер |может решить отправить результаты (или просто подтверждение о выполнении) |назад реквестеру. Но при использовании техники базовой отправки |сообщений, описанной выше, нет такого средства, которое соединило бы |требование отправителя с ответом провайдера службы. Если реквестер не |ожидает ответа перед тем, как продолжить работу, должен использоваться |какой-нибудь механизм, чтобы связать каждый ответ с соответствующим |требованием. От разработчика не требуется создания такого механизма, |так как MQSeries обеспечивает идентификатор корреляции, который позволяет |коррелировать сообщения при обмене.
|Существует несколько способов, в которых можно использовать этот механизм, |но самый простой заключается в том, что реквестер помечает сообщения, |используя известный идентификатор корреляции, например, так:
|Пример 17:
|DB2MQ.MQSEND ('myRequester','myPolicy','SendStatus:cust1','Req1')
|Этот оператор добавляет заключительный параметр Req1 в вышеуказанный |оператор MQSEND, чтобы указать идентификатор корреляции для требования.
|Чтобы получить ответ на это конкретное требование, воспользуйтесь |оператором MQRECEIVE для выборочного получения первого сообщения, |определенного указанной службой, соответствующей данному идентификатору |корреляции, так:
|Пример 18:
|DB2MQ.MQRECEIVE('myReceiver','myPolicy','Req1')
|Если программа, обслуживающая требование, занята, а реквестер выдает |указанный выше оператор MQRECEIVE перед отправкой ответа, не будет найдено ни |одного сообщения, удовлетворяющего данному идентификатору корреляции.
|Чтобы получить и требование службы, и идентификатор корреляции, |используется примерно такой оператор:
|Пример 19:
|SELECT msg, correlid FROM table (DB2MQ.MQRECEIVEALL('aServiceProvider','myPolicy',1)) t
|Он возвращает от провайдера aServiceProvider сообщение и идентификатор |корреляции первого требования.
|После того, как служба выполнена, она отправляет сообщение-ответ в очередь |реквестера. В это время реквестер службы может заниматься другой |работой. Фактически нет никакой гарантии, что на начальное требование |службы будет дан ответ в установленное время. Сроками ожидания уровня |программы, подобными этому, должен управлять разработчик; за обнаружение |ответа ответственен реквестер.
|Преимущество такой асинхронной обработки, не зависящей от времени, состоит |в том, что реквестер и провайдер службы выполняют ее полностью независимо друг |от друга. Этот способ годится и для сред, в которых программы |соединяются лишь периодически, и для сред, более ориентированные на пакеты, в |которых перед обработкой накапливается множество требований или |ответов. Такое накопление часто используется в средах хранилищ данных |для периодического обновления хранилища данных или при оперативном хранении |данных.
|Другой обычный сценарий в интеграции программ состоит в том, что одна |программа уведомляет другие программы о представляющих интерес |событиях. Этого легко добиться, послав сообщение в очередь, которую |отслеживает другая программа. Содержание сообщения может быть заданной |пользователем строкой или состоять из столбцов базы данных. Часто |требуется просто послать сообщение; для этого используется функция |MQSEND. Если такое сообщение необходимо послать одновременно нескольким |получателям, можно воспользоваться средством интерфейса MQSeries AMI Список |распределения.
|Список распределения задается при помощи инструмента AMI |Administration. Такой список содержит названия отдельных служб. |Сообщение, посланное в список распределения, отправляется каждой службе из |этого списка. Это особенно полезно, если известно, что каждое сообщение |всегда будет представлять интерес для нескольких служб. В следующем |примере показана отправка сообщения в список распределения |interestedParties:
|Пример 20:
|DB2MQ.MQSEND('interestedParties','интересная для всех информация');
|Когда требуется более сложное управление сообщениями для конкретных службы, |лучше использовать средство Publish/Subscribe - публикация/подписка. |Системы Publish/Subscribe,как правило, предоставляют масштабируемую, |защищенную среду, в которой множество подписчиков могут зарегистрироваться на |получение сообщений от ряда издателей. Для поддержки этой возможности |может использоваться интерфейс MQPublish в совокупности с MQSeries Integrator |или MQSeries Publish/Subscribe.
|MQPublish позволяет пользователям по желанию задать тему, которая будет |связана с сообщением. Темы позволяют подписчикам более точно описать |сообщения, которые будут приниматься. Используется следующая |последовательность действий: |
|Чтобы опубликовать данные с использованием всех умолчаний, не задавая |тему, следует воспользоваться примерно таким оператором:
|Пример 21:
|SELECT DB2MQ.MQPUBLISH(LASTNAME || ' ' || FIRSTNAME || ' ' || DEPARTMENT|| ' ' ||char(AGE)) | FROM EMPLOYEE | WHERE DEPARTMENT = '5LGA'
|Оператор, который полностью задает все параметры и упрощает сообщение, |чтобы в нем содержалась только фамилия, выглядит так:
|Пример 22:
|SELECT DB2MQ.MQPUBLISH('HR_INFO_PUB', 'SPECIAL_POLICY', LASTNAME, 'ALL_EMP:5LGA', 'MANAGER') | FROM EMPLOYEE | WHERE DEPARTMENT = '5LGA'
|Этот оператор выпускает сообщения для издательской службы HR_INFO_PUB с |использованием правил обслуживания SPECIAL_POLICY. В сообщениях |указывается, что тема отправителя - MANAGER. В строке темы показана |возможность указания нескольких тем, разделенных двоеточиями |':'. В этом примере использование двух тем позволяет |подписчикам для получения сообщений зарегистрировать тему ALL_EMP или только |5LGA.
|Для получения опубликованных сообщений сначала вы должны зарегистрировать |свою заинтересованность в сообщениях на данную тему, и указать имя службы |подписчика, куда следует посылать сообщения. Важно отметить, что службы |подписчика интерфейса AMI определяет службу посредника и службу |получателя. Служба посредника определяет, как подписчик взаимодействует |с посредником публикации/подписки, а служба получателя - куда будут посылаться |сообщения, удовлетворяющие требованию подписчика. Следующий оператор |регистрирует заинтересованность в теме ALL_EMP.
|Пример 23:
|DB2MQ.MQSUBSCRIBE('aSubscriber', 'ALL_EMP')
|После подписки программы сообщения с темой ALL_EMP будут отправляться в |службу получателя, определенную службой подписчика. У программы может |быть несколько одновременных подписок. Для сообщений, отвечающих |подписке, можно пользоваться любой стандартной функцией получения |сообщений. Например, если служба подписчика aSubscriber задает, что |служба получателя - aSubscriberReceiver,тогда следующий оператор прочтет |первое сообщение, не удаляя его:
|Пример 24:
|DB2MQ.MQREAD('aSubscriberReceiver')
|Чтобы задать и сообщения, и темы, под которыми они были выпущены, можно |воспользоваться одной из табличных функций. Следующий оператор может |получить первые пять сообщений из службы aSubscriberReceiver и вывести и |сообщения, и их темы:
|Пример 25:
|SELECT t.msg, t.topic FROM table (DB2MQ.MQRECEIVEALL('aSubscriberReceiver',5)) t
|Для чтения всех сообщений с темой ALL_EMP можно применить средства |SQL:
|Пример 26:
|SELECT t.msg FROM table (DB2MQ.MQREADALL('aSubscriberReceiver')) t | WHERE t.topic = 'ALL_EMP'
|Если вы больше не нуждаетесь в подписке на конкретную тему, нужно явно |отменить подписку, воспользовавшись таким оператором:
|Пример 27:
|DB2MQ.MQUNSUBSCRIBE('aSubscriber', 'ALL_EMP')
|После запуска такого оператора посредник публикации/подписки больше не |будет поставлять сообщения, отвечающие критериям данной подписки.
|Другим важным способом передачи сообщений базы данных является |автоматическая публикация сообщений. С помощью триггера DB2 можно |автоматически публиковать сообщения при вызове триггера. Существуют и |другие способы автоматической публикации сообщений, но подход с использованием |триггера предоставляет администраторам или разработчикам большую свободу в |конструировании содержания сообщений и гибкость при определении действий |триггера. Как и при любом другом использовании триггера, следует |обратить внимание на частоту и стоимость его работы. Следующие примеры |показывают, как можно использовать триггеры с функциями DB2 MQSeries.
|В примере ниже показано, как просто при помощи триггера публиковать |сообщение при найме каждого нового служащего. Любые пользователи или |программы, подписывающиеся в службе HR_INFO_PUB с регистрацией темы NEW_EMP, |будут получать сообщение, содержащее дату, имя и отдел для каждого нового |сотрудника.
|Пример 28:
|CREATE TRIGGER new_employee AFTER INSERT ON employee REFERENCING NEW ASn | FOR EACH ROW MODE DB2SQL | VALUES DB2MQ.MQPUBLISH('HR_INFO_PUB&', 'NEW_EMP', | current date || ' ' || LASTNAME || ' ' || DEPARTMENT)