Ja. Een LOB is een aanwijzer/verwijzing naar een geheugen/schijfopslag. U moet eerst de opslag "memalloc()" (... initialiseren) en de aanwijzer/referentie toewijzen aan uw LOB-variabele. Dat is wat dbms_lob.createTemporary()
is voor. Tenzij u een LOB-variabele initialiseert met een geldige LOB-locator, mislukken al uw bewerkingen op die LOB-variabele met ORA-22275: invalid LOB locator specified
.
Verbetering: Laat je PL/SQL-functie een beetje refactoren:(En houd er rekening mee dat ik een dummy-query heb gebruikt voor de last_60_cpu_cursor
cursor. Gebruik de cursor niet opnieuw, maar gebruik die van uzelf! :-))
create or replace
function statistics_function
( namein in varchar2 )
return clob
is
line clob;
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => line, cache => true, dur => dbms_lob.call);
for cv in last_60_cpu_cursor loop
dbms_lob.append(line, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(line, 'last_60_cpu'||chr(10));
return line;
end statistics_function;
- Je hoeft de cursor niet te openen+ophalen+sluiten. Een gewone cursor-loop doet het prima (zo niet zelfs beter, dankzij de impliciete bulk-fetching onder de motorkappen).
- Verklaar de tijdelijke LOB expliciet als gecached (
cache => true
; zoals je al hebt). Dit zorgt ervoor dat gegevensblokken worden toegevoegd aan de LOB in het geheugen, in plaats van dat ze op schijf worden toegevoegd (cache => false
). - Voeg de tekenreeksen samen die aan de LOB moeten worden toegevoegd om het aantal aanroepen naar de
dbms_lob.append()
te minimaliseren . - Verwijder de
dbms_output.put_line()
vanuit je functie. In het geval van LOB-inhoud groter dan 32K, zou dit sowieso een uitzondering veroorzaken.
Nadat u klaar bent met het terugbrengen van de LOB naar uw Java-omgeving, de tijdelijke LOB vrijmaken . (Ik ben geen Java-man, kan het Java-codefragment zelf niet schrijven.)
Ook heb je een conceptuele fout in je Java-code; het registreren van de terugkeer van de functie als Types.VARCHAR
is fout. Gebruik liever het het speciale CLOB-type van Oracle
. (Ik heb die in C# gezien, Java moet ze ook hebben.)
Er is ook een prestatieprobleem met uw oplossing. Uw functie retourneert een LOB. In PL/SQL wordt elke functiewaarde teruggestuurd naar de aanroeper als een diepe kopie van de interne waarde. Als u dus een LOB van een functie retourneert, wordt de LOB-inhoud op de achtergrond gedupliceerd met een nieuwe LOB-locator (/pointer/reference). Je zou moeten gebruiken U kunt overwegen om een opgeslagen procedure te gebruiken in plaats van een functie en de LOB door te geven aan Java als een out nocopy
parameter. Het opgeslagen proces ziet er dan als volgt uit:
create or replace
procedure statistics_function
( namein in varchar2
, lob_out out nocopy clob )
is
cursor last_60_cpu_cursor is
select 1 as last_60_cpu, sysdate as last_60_event_date
from dual
;
begin
dbms_lob.createtemporary(lob_loc => lob_out, cache => true, dur => dbms_lob.session);
for cv in last_60_cpu_cursor loop
dbms_lob.append(lob_out, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
end loop;
dbms_lob.append(lob_out, 'last_60_cpu'||chr(10)||chr(10));
end statistics_function;
Hoe uw Java-oproep eruitziet, is aan u en JDBC-document ; maar een LOB die op deze manier wordt geretourneerd, zou zeker betekenen dat er geen achtergrondinhoud wordt gekopieerd. Natuurlijk blijft de noodzaak om de toegewezen tijdelijke LOB vrij te maken nog steeds van kracht.