Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak korzystać z Oracle DBMS_ALERT w Oracle APEX?

Stworzyłbym demo na apex.oracle.com, ale ponieważ potrzebujesz grantu na wykonanie na dbms_alert, będzie to tylko tekstowe.

Możesz posunąć się dość daleko z całą konfiguracją, więc uważam to za podstawę do budowania. Na przykład pracowałem tylko z jednym alertem. W swojej próbce możesz chcieć użyć wielu zdarzeń, aby wychwycić różne alerty postępu. Dzieje się tak z tego prostego powodu, że aby zwrócić coś klientowi (odpowiedź ajax), wywołanie zwrotne ajax musi zostać 'zamknięte'. Więc kiedy złapiesz alert i chcesz go zwrócić, musisz napisać do bufora i musi zostać zwrócony. Oznacza to, że przestaniesz też słuchać wydarzenia (czytaj:w apesie, powinieneś!).

Rozważ przepływ w ten sposób:wykonasz wywołanie ajax i będziesz miał proces wywołania zwrotnego ajax, który rejestruje zainteresowanie zdarzeniem. Następnie czekasz na pojawienie się alertu. Łapiesz go i zwracasz, zapisując go w buforze http (htp.p ). To koniec kodu i apex opróżni bufor, a następnie wywołanie ajax odbierze odpowiedź i będziesz mógł zarządzać tym zwrotem.
Nie zapominaj jednak:apex używa puli połączeń i bazy danych sesje nie są połączone bezpośrednio, ale są ponownie wykorzystywane przez cały czas. Nie chcesz „pozostawiać” sesji bazy danych „zabrudzonej”. Będziesz musiał również wyrejestrować swoje zainteresowanie alertem. Stwarza to również powód do używania unikalnych identyfikatorów dla alertów – alerty mogą być rejestrowane w różnych sesjach (bazy danych), więc jeśli byłaby to strona, z której wielu użytkowników może korzystać do śledzenia postępu ich procesu, nie chcesz, aby zakłócały alerty innych użytkowników.

Jednak ten ulotny charakter zainteresowania oznacza również, że będą „przerwy” między różnymi wykonanymi połączeniami ajaxowymi. Jeśli chcesz wysłuchać wielu alertów, a alerty te mogą być bardzo blisko siebie upakowane, istnieje szansa, że ​​jeden z nich przegapisz. Powiedzmy, że 2 alerty są oddalone od siebie o 1 ms:pierwszy zostanie przechwycony, zgłoszony do połączenia ajax, które będzie musiało od razu rozpocząć nowe połączenie, aby nasłuchiwać kolejnych alertów. Ale ponieważ w tym krótkim czasie nie było aktywnego słuchacza, następny alert mógł zostać pominięty. Teraz – prawdopodobnie jest to problem polegający na tym, że uruchamiasz wiele alertów w ramach tego samego modułu obsługi. Jeśli użyjesz wielu programów obsługi i uruchomisz wywołania ajax dla wszystkich w tym samym czasie, wszystkie zostaną obsłużone na czas. Oczywiście istnieją rozwiązania dla obu. Wyobrażam sobie, że korzystając tylko z jednego programu obsługi, można przechwycić wszystkie alerty w kolekcji i sprawdzić je, jeśli już wysłałeś odpowiedź na określony alert, czy nie, i czy kontynuować sprawdzanie, czy nie. W przypadku wielu programów obsługi możesz użyć unikalnego identyfikatora i dodać do niego różne statusy.

Oto rzeczywisty kod, którego użyłem w moim lokalnym POC.

Przegląd:Mam 3 przyciski:1 do generowania identyfikatora alertu, dla którego użyłem sekwencji. Kolejny przycisk do rozpoczęcia nasłuchiwania zdarzenia i kolejny przycisk do wysyłania alertu.

Kod JS przycisku NEW_ALERT_ID:

apex.server.process("NEW_ALERT").done(function(pdata){
$s("P1_ALERT_ID",pdata.alertId);
})

Kod JS przycisku START_LISTEN:

apex.server.process("LISTEN_ALERT",{x01:$v("P1_ALERT_ID")},{timeout:(31*1000)})
.done(function(pdata){
  if (pdata.success ){
      alert('Caught alert: ' + pdata.message);
  } else {
      alert("No alerts caught during wait on database. You may want to continue listening in...")
  }
})
.fail(function(jqXHR, textStatus){
    if(textStatus === 'timeout')
    {     
        alert('Call should have returned by now...'); 
        //do something. Try again perhaps?
    }
});

Kod JS przycisku SEND_ALERT:

apex.server.process("SEND_ALERT",{x01:$v("P1_ALERT_ID")},{dataType:"text"});

Procesy wywołania zwrotnego AJAX:

NEW_ALERT:

htp.p('{"alertId":'||alert_seq.nextval()||'}');

LISTEN_ALERT:

declare
  alert_id number := apex_application.g_x01;
  msg varchar2(2000);
  stat pls_integer;
  keep_looping boolean := true;
  insurance binary_integer := 0; -- prevent an infinite loop

  onecycle binary_integer := 3; -- one cycle of waiting, in seconds
  maxcycles binary_integer := 10; -- in this session, the max amount of cycles to wait
begin
  dbms_alert.register(alert_id);

  while keep_looping
  loop
    insurance := insurance + 1;

    dbms_alert.waitone(alert_id, msg, stat, onecycle);
    if stat = 1 then
      apex_debug.message('timeout occured, going again');
    else
      apex_debug.message('alert: '||msg);
      keep_looping := false;
    end if;

    exit when insurance = maxcycles;    
  end loop;


  if keep_looping then
    -- we waited a really long time now. It may be a good idea to return this info to the client and let it start a new call
    htp.p('{"success":false,"message":"No alert during wait on database"}');
  else
    htp.p('{"success":true,"message":"'||msg||'"}');
  end if;
end;

SEND_ALERT:

declare
  alert_id number := apex_application.g_x01;
begin
  dbms_alert.signal(alert_id, 'alert sent at '||to_char(systimestamp, 'HH24:MI:SS FF6'));
end;

Więc najpierw otrzymywałem identyfikator alertu, potem zacząłem słuchać, a potem w pewnym momencie wysłałem alert (lub nie). Jest to jednak szkielet i będzie wymagał dalszego dopracowania w twojej aktualnej konfiguracji.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Niejednoznaczność w połączeniach lewych (tylko wyrocznia?)

  2. Obliczanie dni świątecznych:liczba sobót i niedziel w zapytaniu o zadany zakres dat w Oracle

  3. Konwersja bazy 36 do bazy 10 tylko przy użyciu SQL

  4. Uzyskaj czas wykonania skryptu sql w Oracle sqlplus

  5. Jak wyświetlić rekordy z tabeli uporządkowanej jak w klauzuli where?