处理 python 和 oracle 之间异常握手的正确方法

Correct way to handle exception handshake between python and oracle

我正在从 Python 调用以下过程,问题是我无法看到块中出现的异常,现在为了重现我已经强制引发异常但我无法在 Python 副脚本

中看到这一点
CREATE OR REPLACE FUNCTION mark_step
(
   batch_id   IN NUMBER
  ,request_id IN VARCHAR2
) RETURN NUMBER IS


BEGIN
   INSERT INTO temp_log VALUES ('entered');
   RAISE no_data_found;

   return 0;
EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO temp_log VALUES ('exception');

END mark_step;

调用此函数的客户端脚本

l_result = cur.callfunc('mark_step', cx_Oracle.STRING,
                                    [batch_id,request_id])



print(l_result)

该函数优雅地处理了异常,并且Python脚本没有获得在异常块上添加 Raise 失败的函数的任何可见性

EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO temp_log VALUES ('exception');
      RAISE;
END mark_step;

在 Python 方面,您可以添加 try , except 块以明确处理异常,以防您尚未这样做

try:   
   l_result = cur.callfunc('credit_ref_mig.mark_step', cx_Oracle.STRING,
                                       [batch_id,request_id])

   print(l_result)
except as e:
   print(e)

我认为没有问题,除了在您的代码中 exception block 中缺少 return value

您的 function 引发的 exceptionfunction 本身包含的 exception block 处理。

演示如下:

正在创建 table

SQL> CREATE TABLE TEMP_LOG (
  2      LOG_   VARCHAR2(50)
  3  );

Table created.

SQL>

正在创建 function,请参阅内嵌注释:

SQL> CREATE OR REPLACE FUNCTION MARK_STEP (
  2      BATCH_ID     IN           NUMBER,
  3      REQUEST_ID   IN           VARCHAR2
  4  ) RETURN NUMBER IS
  5  BEGIN
  6      INSERT INTO TEMP_LOG VALUES ( 'entered' );
  7      RAISE NO_DATA_FOUND; -- error raised by this statement will be handeled by following exception block
  8      RETURN 0;
  9  EXCEPTION
 10      WHEN OTHERS THEN
 11          INSERT INTO TEMP_LOG VALUES ( 'exception' );
 12          RETURN -1; -- this is misssing in your code
 13  END;
 14  /

Function created.

SQL>

调用函数:

SQL> SET SERVEROUT ON
SQL>
SQL> DECLARE
  2      CNT   NUMBER;
  3  BEGIN
  4      CNT := MARK_STEP(1, 'v');
  5      DBMS_OUTPUT.PUT_LINE('result := ' || CNT);
  6      COMMIT;
  7  END;
  8  /
result := -1

PL/SQL procedure successfully completed.

SQL>

检查temp_log中的数据 table:

SQL> SELECT * FROM TEMP_LOG;

LOG_
--------------------------------------------------
entered
exception

SQL>

看到两个部分都已执行,function 的结果也是 -1

现在,如果您想将错误报告给外部调用程序,那么您可以删除整个 exception block,如下所示:

SQL> CREATE OR REPLACE FUNCTION MARK_STEP (
  2      BATCH_ID     IN           NUMBER,
  3      REQUEST_ID   IN           VARCHAR2
  4  ) RETURN NUMBER IS
  5  BEGIN
  6      INSERT INTO TEMP_LOG VALUES ( 'entered' );
  7
  8      COMMIT; -- added commit to see if it is working or not
  9      RAISE NO_DATA_FOUND; -- error raised by this statement will be handeled by following exception block
 10      RETURN 0;
 11  --EXCEPTION
 12  --    WHEN OTHERS THEN
 13  --        INSERT INTO TEMP_LOG VALUES ( 'exception' );
 14  --        RETURN -1; -- this is misssing in your code
 15  END;
 16  /

Function created.

SQL>

调用更新后的 function 并检查 temp_log table 中的数据。

SQL> TRUNCATE TABLE TEMP_LOG;

Table truncated.

SQL> SET SERVEROUT ON
SQL>
SQL> DECLARE
  2      CNT   NUMBER;
  3  BEGIN
  4      CNT := MARK_STEP(1, 'v');
  5      DBMS_OUTPUT.PUT_LINE('result := ' || CNT);
  6      COMMIT;
  7  END;
  8  /
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "TEJASH.MARK_STEP", line 9
ORA-06512: at line 4


SQL> SELECT * FROM TEMP_LOG;

LOG_
--------------------------------------------------
entered

SQL>

看,现在抛出了 errorraise exception 上面的所有代码都按预期工作了。

我希望,你觉得这很有用。

干杯!!