Ja. Ein LOB ist ein Zeiger/eine Referenz auf einen Arbeitsspeicher/Plattenspeicher. Sie müssen zuerst den Speicher "memalloc()" (... initialisieren) und den Zeiger / die Referenz Ihrer LOB-Variablen zuweisen. Das ist dbms_lob.createTemporary()
ist für. Wenn Sie eine LOB-Variable nicht mit einem gültigen LOB-Locator initialisieren, schlagen alle Ihre Operationen an dieser LOB-Variable mit ORA-22275: invalid LOB locator specified
fehl .
Verbesserung: Lassen Sie Ihre PL/SQL-Funktion ein wenig umgestalten:(Und bitte beachten Sie, dass ich eine Dummy-Abfrage für den last_60_cpu_cursor
verwendet habe Mauszeiger. Verwenden Sie den Cursor nicht wieder, verwenden Sie Ihren eigenen! :-))
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;
- Sie müssen den Cursor nicht öffnen+holen+schließen. Eine normale Cursor-Schleife wird gut funktionieren (wenn nicht sogar besser, dank des impliziten Bulk-Fetching unter den Hauben).
- Deklarieren Sie das temporäre LOB ausdrücklich als zwischengespeichert (
cache => true
; wie du schon hast). Dadurch wird sichergestellt, dass Datenblöcke dem LOB im Arbeitsspeicher hinzugefügt werden, anstatt auf der Festplatte hinzugefügt zu werden (cache => false
). - Verketten Sie die an das LOB anzuhängenden Zeichenfolgen, um die Anzahl der Aufrufe von
dbms_lob.append()
zu minimieren . - Entfernen Sie
dbms_output.put_line()
aus Ihrer Funktion. Bei LOB-Inhalten größer als 32 KB würde dies sowieso eine Ausnahme auslösen.
Nachdem Sie das LOB wieder an Ihre Java-Umgebung zurückgesendet haben, befreien Sie das temporäre LOB . (Ich bin kein Java-Typ, kann das Java-Code-Snippet nicht selbst schreiben.)
Außerdem haben Sie einen konzeptionellen Fehler in Ihrem Java-Code; Registrieren der Rückgabe der Funktion als Types.VARCHAR
ist falsch. Sie sollten lieber den den dedizierten CLOB-Typ von Oracle
verwenden . (Ich habe die in C# gesehen, Java muss sie auch haben.)
Außerdem gibt es ein Leistungsproblem bei Ihrer Lösung. Ihre Funktion gibt ein LOB zurück. In PL/SQL wird jeder Funktionswert als tiefe Kopie des inneren Werts an seinen Aufrufer zurückgegeben. Wenn Sie also ein LOB von einer Funktion zurückgeben, werden die LOB-Inhalte im Hintergrund mit einem neuen LOB-Locator (/Zeiger/Referenz) dupliziert. Sie sollten verwenden Sie können eine gespeicherte Prozedur anstelle einer Funktion verwenden und das LOB als out nocopy
an Java übergeben Parameter. Die gespeicherte Prozedur würde dann so aussehen:
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;
Wie Ihr Java-Aufruf aussehen würde, liegt bei Ihnen und JDBC-Dokument ; aber ein auf diese Weise zurückgegebenes LOB würde mit Sicherheit bedeuten, dass kein Hintergrundinhalt kopiert wird. Natürlich besteht weiterhin die Notwendigkeit, das zugewiesene temporäre LOB freizugeben.