ORA-22275:指定了无效的LOB定位符

Pet*_*zov 2 oracle plsql oracle10g oracle11g

我有很大的Oracle函数,用于计算6个表中的数据.

create or replace FUNCTION STATISTICS_FUNCTION(NAMEIN IN VARCHAR2

)
RETURN CLOB
AS
    LAST_60_CPU NUMBER;
    .............

    LINE CLOB;

    CURSOR LAST_60_CPU_CURSOR IS
     .................

BEGIN

    LINE := EMPTY_CLOB();
    DBMS_LOB.CREATETEMPORARY(LINE,true);
  OPEN LAST_60_CPU_CURSOR;
   LOOP
      FETCH LAST_60_CPU_CURSOR INTO LAST_60_EVENT_DATE, LAST_60_CPU;
      ....................
      DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_EVENT_DATE));
      DBMS_LOB.APPEND(LINE, 'I');
      DBMS_LOB.APPEND(LINE, TO_CHAR(LAST_60_CPU));
      DBMS_LOB.APPEND(LINE, CHR(10));
   END LOOP;
   CLOSE LAST_60_CPU_CURSOR;
   DBMS_LOB.APPEND(LINE, 'LAST_60_CPU');
   DBMS_LOB.APPEND(LINE, CHR(10));
.......................................................

-------------------------------------
DBMS_OUTPUT.PUT_LINE(LINE);

  RETURN LINE;
END STATISTICS_FUNCTION;
Run Code Online (Sandbox Code Playgroud)

我使用这个Java代码来调用函数:

public void callFunction() throws SQLException
{
// initialize the driver and try to make a connection

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "admin", "qwerty");

// prepareCall uses ANSI92 "call" syntax
CallableStatement cstmt = conn.prepareCall("{? = call AGENT_STATISTICS_FUNCTION(?)}");

// get those bind variables and parameters set up
cstmt.registerOutParameter(1, Types.VARCHAR);
cstmt.setString(2, "agent");

// now we can do it, get it, close it, and print it
cstmt.execute();
String result = cstmt.getString(1);
conn.close();
System.out.println(result);
}
Run Code Online (Sandbox Code Playgroud)

我厌倦了在没有这一行的情况下调用函数:

DBMS_LOB.CREATETEMPORARY(LINE,true);
Run Code Online (Sandbox Code Playgroud)

但我得到错误:

Connecting to the database local.
ORA-22275: invalid LOB locator specified
ORA-06512: at "SYS.DBMS_LOB", line 639
ORA-06512: at "ADMIN.STATISTICS_FUNCTION", line 596
ORA-06512: at line 7
Process exited.
Disconnecting from the database local.
Run Code Online (Sandbox Code Playgroud)

如果没有DBMS_LOB.CREATETEMPORARY(LINE,true),你知道为什么我会收到这个错误吗?

nop*_*svk 6

你知道为什么我没有这个错误DBMS_LOB.CREATETEMPORARY(LINE,true);吗?

是.LOB是指向内存/磁盘存储的指针/引用.您首先需要"memalloc()"(...初始化)存储,将指针/引用分配给您的LOB变量.这dbms_lob.createTemporary()是为了什么.除非使用有效的LOB定位器初始化LOB变量,否则对该LOB变量的所有操作都将失败ORA-22275: invalid LOB locator specified.

增强:你的PL/SQL函数有点重构:(请注意我对last_60_cpu_cursor光标使用了一个虚拟查询.不要重复使用光标,使用你自己的!:-))

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;
Run Code Online (Sandbox Code Playgroud)
  1. 您无需打开+ fetch +关闭光标.一个常规的游标循环就可以了(如果不是更好的话,多亏了引擎盖下的隐式批量获取).
  2. 明确地将临时LOB声明为缓存(cache => true;就像您已经拥有的那样).这可确保将数据块添加到内存中的LOB,而不是添加到磁盘(cache => false)上.
  3. 连接要附加到LOB的字符串,以便最小化对LOB的调用次数dbms_lob.append().
  4. dbms_output.put_line()从您的功能中删除.在LOB内容大于32K的情况下,无论如何都会抛出异常.

此外,在完成将LOB交付给Java环境后,释放临时LOB.(我不是Java人,不能自己编写Java代码片段.)

此外,您的Java代码中存在概念错误; 注册函数的返回Types.VARCHAR错误.您应该使用Oracle的专用CLOB类型.(我在C#中看过那些,Java也必须有它们.)

此外,您的解决方案存在一个性能问题.您的函数返回LOB.在PL/SQL中,每个函数值作为内部值的深层副本返回给其调用者.因此,如果从函数返回LOB,则LOB内容将在后台与新的LOB定位符(/ pointer/reference)重复.你应该用您可以考虑使用存储过程而不是函数,并将LOB作为out nocopy参数传递给Java .存储过程将如下所示:

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;
Run Code Online (Sandbox Code Playgroud)

你的Java调用看起来如何,取决于你和JDBC doc ; 但是,当然,以这种方式返回的LOB意味着没有复制背景内容.当然,释放分配的临时LOB的需要仍然适用.