|
Программирование >> Oracle
Пакеты DBMS ALERT и DBMS PIPE 1563 Пакет DBMS ALERT Пакет DBMS ALERT - очень небольшой и содержит всего семь точек входа. Я опишу здесь шесть наиболее интересных. Если для приложения требуется получить уведомление, то наиболее существенными окажутся следующие подпрограммы. REGISTER. Зарегистрироваться на получение указанного сигнала. В сеансе можно многократно вызывать подпрограмму REGISTER c разными именами сигналов, чтобы получать уведомления при наступлении одного из нескольких событий. REMOVE. Снять регистрацию на получение сигнала, чтобы сервер не пытался уведомить о наступлении события. REMOVEALL. Снять для сеанса регистрацию на получение всех сигналов. WAITANY. Ожидать уведомления о сигналах, на получение которых сеанс зарегистрирован. Эта подпрограмма выдает имя поступившего сигнала и обеспечивает доступ к сопровождающему его короткому сообщению. Ждать можно либо заданное время, либо вообще не ждать (что позволяет из приложения эпизодически опрашивать систему, чтобы узнать, не произошло ли событие, не блокируя при этом дальнейшую обработку ожиданием события). WAITONE. Ожидать уведомления об указанном сигнале. Как и в случае WAITANY, ждать можно определенное время или вообще не ждать. Приложение, желающие послать сигнал, или уведомить о событии, может сделать это с помощью следующей подпрограммы. SIGNAL. Послать сигнал о наступлении события при фиксации текущей транзакции. При откате посылка сигнала отменяется. Итак, пакет DBMS ALERT очень просто использовать. Клиентское приложение, для которого требуется получение уведомления о событии, может содержать код вида: tkyte@TKE816> begin 2 dbmsalert. register ( MyMert) ; 3 end; PL/SQL procedure successfully completed. tkyte@TKYTE816>set serveroutput on tkyte@TKYTE816> declare 2 l status number; 3 l msg varchar2(1800); 4 begin 5 dbms alert.waitone(name => MyMert, 6 message => l msg, 7 status => l status, 8 timeout => dbms alert.maxwait); 9 10 if (l status = 0) 11 then 12 dbms output.put line(Сообщение события: l msg); 1564 Приложение А 13 end if; 14 end; 15 / Мы зарегистрировались на получение сигнала MyAlert, а затем вызвали процедуру DBMS ALERT.WAITONE, ожидая поступление этого сигнала. Обратите внимание, что, поскольку использована константа DBMS ALERT.MAXWAIT из пакета DBMS ALERT, сеанс при выполнении этого вызова начнет ждать бесконечно. Сеанс блокируется в ожидании соответствующего события. Можно задать для клиентского приложения период ожидания 0 секунд, что исключит ожидание, и опрашивать сервер о наступлении события. Например, приложение Oracle Forms может использовать ежеминутно срабатывающий таймер, вызывающий процедуру DBMS ALERT.WAITONE, чтобы узнать, не произошло ли некоторое событие. Если событие произошло, экран приложения меняется. Можно с такой же частотой активизировать поток Java, проверяющий, не произошло ли событие, и обновляющий совместно используемую структуру данных, и т.д. Чтобы послать этот сигнал, достаточно выполнить следующее: tkyte@TK[E816> exec dbms alert.signal(MyMert, Hello World); PL/SQL procedure successfully completed. tkyte@TKYTE816> commit; Commit complete. в другом сеансе. В сеансе, заблокированном в ожидании события, вы должны немедленно увидеть: 15 / Сообщение события: Hello World PL/SQL procedure successfully completed. То есть сеанс больше не заблокирован. Я продемонстрировал наиболее типичн1й вариант использования пакета DBMS ALERT. Сеансы ждут сигнала с определенным именем. Пока в пославшем сигнал сеансе транзакция не зафиксирована, уведомление о сигнале не посылается. В этом легко убедиться с помощью двух сеансов SQL*Plus. Работа с сигналами становится более интересной, если задаться следующими вопросами. Что происходит, если несколько сигналов более-менее одновременно отправляются разными сеансами? Что происходит, если посыпать сигнал несколько раз: сколько сигналов будет сгенерировано в конечном итоге? Что происходит, если более одного сеанса пошлет сигнал, после того как я зарегистрировался на его получение, но до вызова одной из процедур ожидания? А что произойдет, если несколько сеансов пошлют сигнал в промежутке между вызовами процедур ожидания? Ответы на эти вопросы позволят выявить побочные эффекты использования сигналов, которые необходимо учитывать. Я также предложу способы избежать некоторых проблем, связанных со всем изложенным выше. Пакеты DBMS ALERT и DBMS PIPE 1565 Одновременные сигналы нескольких сеансов Если повторно выполнить рассмотренный пример, зарегистрировавшись на получение сигнала MyAlert и ожидая его в одном сеансе, а затем запустить два дополнительных сеанса, можно будет увидеть, что произойдет при одновременной передаче сигналов из нескольких сеансов. На этот раз в обоих сеансах мы выполним: tkyte@TKYTE816> exec dbms alert.signal(MyMert, Hello World); (транзакции не фиксируются). Окажется, что сеанс, пославший сигнал вторым, заблокирован. Это показывает, что если N сеансов одновременно пытаются послать один и тот же сигнал, N-1 из них будут заблокированы при вызове DBMS ALERT.SIGNAL. Продолжит работу только один из сеансов. Сигналы должны посылаться последовательно, и следует позаботиться о предотвращении подобных проблем. Должна обеспечиваться возможность одновременного доступа к базе данных множества сеансов. Пакет DBMS ALERT - одно из тех средств, которое существенно снижает масштабируемость по этому показателю. Если создать для таблицы триггер на событие INSERT, а в коде этого триггера использовать вызов DBMS ALERT.SIGNAL, при выполнении множества операторов INSERT все они выстроятся в очередь, если хоть один сеанс зарегистрировался на получение соответствующего сигнала. Поэтому имеет смысл ограничить количество сеансов, посылающих сигналы. Например, при получении оперативных данных из внешнего источника пакет DBMS ALERT вполне можно использовать, если данные в таблицу вставляет только один сеанс. Если же речь идет о таблице проверки, в которую часто вставляют данные все сеансы, средства пакета DBMS ALERT лучше не использовать. Один из способов избежать выстраивания сеансов в очередь - использовать пакет DBMS JOB (которому посвящен специальный раздел в этом приложении). Можно написать процедуру, действия которой будут сводиться к передаче сигнала и фиксации транзакции: tkyte@TKYTE816> create table alertmessages 2 (job id int primary key, 3 alert name varchar2(3 0), 4 message varchar2(2000) Table created. tkyte@TKYTE816> create or replace procedure backgroundalert(p job in int) 2 as 3 lrec alert messages%rowtype; 4 begin 5 select * into l rec from alert messages where job id = p job; 6 7 dbms alert.signal(l rec.alert name, l rec.message); 8 delete from alert messages where job id = p job; 9 commit; 10 end; 11 / Procedure created.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |