Oracle
 sql >> Datenbank >  >> RDS >> Oracle

ORA-22275:Ungültiger LOB-Locator angegeben

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;
  1. 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).
  2. 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 ).
  3. Verketten Sie die an das LOB anzuhängenden Zeichenfolgen, um die Anzahl der Aufrufe von dbms_lob.append() zu minimieren .
  4. 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.