oracle如何捕捉从流水线函数从 Java 调用的 PL/SQL 错误

标签: Java Oracle
发布时间: 2017/4/15 0:01:19
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

在我们基于 Oracle(11g) 的应用程序中,我们也利用重流水线功能。现在事实错误报告从这种功能是困难的如下面的 (削减) 示例中所示。 程序的存在是为了从 Java,调用,它应收到任何地方在 PL/SQL 执行过程中发生的错误。

ORACLE 的一部分︰

set serveroutput on

create table dummy (id NUMBER);

create or replace package mytest
as
        type t_rec is record (id integer);
        type t_tab is table of t_rec;
        type t_ref_cur IS REF CURSOR RETURN t_rec;

        function foo
        return t_tab pipelined;

        procedure bar( p_ref_cur out t_ref_cur);
end mytest;
/
show errors

create or replace package body mytest
as
        function foo
        return t_tab pipelined
        is
                v_cur SYS_REFCURSOR;
                v_sql varchar2(2000);
                v_rec t_rec;
        begin
                v_sql := 'select wrong_column from DUMMY';
                open v_cur for v_sql;
                loop
                        fetch v_cur into v_rec;
                        exit when v_cur%notfound;

                        pipe row (v_rec);
                end loop;
        exception
                when no_data_needed then
                        null;
                when others then
                        dbms_output.put_line(SQLCODE||' '||sqlerrm );
                        raise no_data_found;
        end foo;

        procedure bar( p_ref_cur out t_ref_cur)
        is
        begin
                open p_ref_cur for select * from table(foo);
        end bar;
end mytest;
/
show errors

-- call procedure bar() from pl/sql
set serveroutput on
declare v_ref_cur mytest.t_ref_cur;
        v_rec mytest.t_rec;
begin
        mytest.bar(v_ref_cur);
        loop
              fetch v_ref_cur into v_rec;
              exit when v_ref_cur%notfound;
              dbms_output.put_line(v_rec.id);
      end loop;
end;
/
show errors

运行上面的函数结果的被所示的异常︰

ORA-00904: "WRONG_COLUMN": invalid column name

Java 部分︰

package test1;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import oracle.jdbc.OracleTypes;

public class start {

    public static void main(String[] args) 
    {
        try 
        {
            Connection con = DriverManager.getConnection("jdbc:oracle:thin:@...", "…", "…");
            CallableStatement stmt = con.prepareCall("BEGIN mytest.bar(?); END;");
            stmt.registerOutParameter(1, OracleTypes.CURSOR);
            stmt.executeQuery();
            ResultSet rs = (ResultSet)stmt.getObject(1);
            while (rs.next())
            {
                System.out.println(rs.getInt(1));
            }
            stmt.close();
            con.close();
        } catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
}

异常不会抓住。结果集是空的。

这是预期的行为吗?我们做错了什么?是一种变通方法存在吗?

解决方法 1:

问题是你抚养 no_data_found ,也不被视为异常中的光标由 bar -它是有效的 select (其中光标你 open 是有效) 返回任何行。当你运行你匿名块时你只看着 dbms_output 调用,不引发的异常-块已成功完成,并且如果你 set serveroutput off 你不会看到任何东西。(编辑︰这老的 AskTom 线程太谈论这种行为)。

为什么你想要改变的异常类型后,你已经抓住它,它还不清楚。我可以看看这样做的唯一原因会让你有,在那里任何错误给你一个空的结果集而不是您必须处理异常的行为。如果这不是你希望发生什么你不应该做,就是最明显一点。如果它是那么你将需要寻找 dbms_output 从 Java 方面的消息。

但我不明白为什么你会想要做,而不是只加注的原始异常︰

            when others then
                    dbms_output.put_line(SQLCODE||' '||sqlerrm );
                    raise;

......或自 dbms_output 总是不可见到客户端,只是没有抓到 others 在所有。它似乎有点毫无意义和直觉来捕捉和壁球异常,当你想要 (Java) 客户机看到它。

在 Java 这边异常然后会是这样 (从 e.getMessage() ):

ORA-00904: "WRONG_COLUMN": invalid identifier
ORA-06512: at "SCHEMA.MYTEST", line 23

也许你想要隐藏的 PL/SQL 堆栈跟踪和只显示单个行的第一次遇到错误,但看起来它将更有助于保持该信息,所以你可以追踪错误。

赞助商