Ja. En LOB er en pointer/reference til en hukommelse/disklager. Du skal først "memalloc()" (... initialisere) lageret, tildele markøren/referencen til din LOB-variabel. Det er hvad dbms_lob.createTemporary()
er for. Medmindre du initialiserer en LOB-variabel med en gyldig LOB-locator, vil alle dine operationer på den LOB-variabel mislykkes med ORA-22275: invalid LOB locator specified
.
Forbedring: Få din PL/SQL-funktion omdannet lidt:(Og bemærk venligst, at jeg brugte en dummy-forespørgsel til last_60_cpu_cursor
cursoren. Genbrug ikke markøren, brug din egen! :-))
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;
- Du behøver ikke at åbne+hent+lukke markøren. En almindelig markørsløjfe vil klare sig fint (hvis ikke endnu bedre, takket være den implicitte bulk-hentning under hætterne).
- Erklærer eksplicit den midlertidige LOB som cachelagret (
cache => true
; som du allerede har). Dette sikrer, at datastykker tilføjes til LOB i hukommelsen i stedet for at blive tilføjet på disken (cache => false
). - Sæt de strenge, der skal tilføjes til LOB'en, for at minimere antallet af kald til
dbms_lob.append()
. - Fjern
dbms_output.put_line()
fra din funktion. I tilfælde af LOB-indhold større end 32K, ville dette alligevel give en undtagelse.
Når du er færdig med at levere LOB tilbage til din Java-env., frigør den midlertidige LOB . (Jeg er ikke en Java-fyr, kan ikke selv skrive Java-kodestykket.)
Du har også en begrebsfejl i din Java-kode; registrering af returneringen af funktionen som Types.VARCHAR
er forkert. Du bør hellere bruge Oracles dedikerede CLOB-type
. (Jeg har set dem i C#, dem skal Java også have.)
Der er også et ydelsesproblem med din løsning. Din funktion returnerer en LOB. I PL/SQL returneres hver funktionsværdi til dens kaldere som en dyb kopi af den indvendige værdi. Derfor, hvis du returnerer en LOB fra en funktion, duplikeres LOB-indholdet i baggrunden med en ny LOB-locator(/pointer/reference). Du bør bruge Du kan overveje at bruge en lagret procedure i stedet for en funktion og videregive LOB til Java som en out nocopy
parameter. Den lagrede proc ville så se sådan ud:
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;
Hvordan vil dit Java-opkald se ud, er op til dig og JDBC-dokument ; men en LOB returneret på denne måde ville helt sikkert betyde ingen kopiering af baggrundsindhold. Behovet for at frigøre den tildelte midlertidige LOB gælder naturligvis stadig.