sql >> Databasteknik >  >> RDS >> Oracle

Hur använder man Oracle DBMS_ALERT i Oracle APEX?

Jag skulle skapa en demo på apex.oracle.com, men eftersom du behöver ett exekveringsbeviljande på dbms_alert måste det endast vara text.

Du kan komma ganska långt med hela installationen, så jag skulle betrakta detta som grunder att bygga vidare på. Till exempel har jag bara arbetat med en varning. I ditt exempel kanske du vill använda flera händelser för att fånga de olika framstegsvarningarna. Detta är av den enkla anledningen att för att returnera något till klienten (ajax-svaret) måste ajax-återuppringningen "stängas". Så när du fångar en varning och vill returnera den måste du skriva till bufferten och den måste returneras. Det betyder att du också kommer att sluta lyssna på evenemanget (läs:i apex, du borde!).

Betrakta flödet så här:du kommer att ringa ett ajax-samtal och ha en ajax-återuppringningsprocess som registrerar intresse för ett evenemang. Sedan väntar du på att en varning ska inträffa. Du fångar den och returnerar den genom att skriva den i http-bufferten (htp.p ). Det är slutet på koden och apex kommer att spola bufferten, ajax-anropet tar sedan upp svaret och du kommer att kunna hantera den returen.
Glöm dock inte:apex använder anslutningspooling och databas sessioner länkas inte direkt utan återanvänds snarare hela tiden. Du vill inte "lämna" en databassession "smutsig". Du måste också avregistrera ditt varningsintresse. Detta gör också ett argument för att använda unika ID för varningar - varningar kan registreras på i olika (databas)sessioner, så om detta skulle vara en sida som flera användare kan använda för att följa framstegen i deras processförlopp, behöver du inte vill att de ska störa andra användares varningar.

Men detta flyktiga intresse innebär också att det kommer att bli "avbrott" mellan olika ajax-samtal. När du vill lyssna efter flera varningar, och dessa varningar kan vara packade väldigt nära varandra, finns chansen att du missar en. Säg att två varningar är placerade med 1 ms från varandra:den första fångas upp, rapporteras till ajax-samtalet, som skulle behöva starta ett nytt samtal direkt för att lyssna efter fler varningar. Men eftersom det inte fanns någon aktiv lyssnare under den korta tiden, kan nästa larm ha missats. Nu - detta är troligen bara ett problem där du avfyrar flera varningar under samma hanterare. Om du skulle använda flera hanterare och starta ajax-anrop för alla dem samtidigt, kommer de alla att hanteras i tid. Det finns lösningar för båda, förstås. Jag föreställer mig att när du bara använder en hanterare kan du fånga alla varningar i en samling och kontrollera om du redan har skickat ett svar för en viss varning eller inte och om du ska fortsätta checka in eller inte. Med flera hanterare kan du använda ett unikt ID och suffixa det med olika statusar.

Så här är lite faktisk kod som jag har använt i min lokala POC.

Översikt:Jag har 3 knappar:1 för att generera ett varnings-id, för vilket jag använde en sekvens. Ytterligare en knapp för att börja lyssna efter en händelse, och ännu en knapp för att skicka en varning.

JS-kod för NEW_ALERT_ID-knapp:

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

JS-kod för knappen 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?
    }
});

JS-kod för knappen SEND_ALERT:

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

AJAX-återuppringningsprocesser:

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;

Så jag skulle först få ett varnings-ID, sedan skulle jag börja lyssna, och sedan någon gång skickade jag en varning (eller inte). Det är dock ett skelett och kommer att behöva ytterligare förfining i din faktiska installation.




  1. Hur övervakar jag SQL Server-tabelländringar med c#?

  2. Varje värde visas i en ny rad HTML-tabell

  3. Problem med Postgres ALTER TABLE

  4. mysql främmande nyckelfel #1452