在oracle中的存储过程中,使用的EXCEPTION并用WHEN OTHERS THEN进行捕获,但是捕获了后就没有办法知道出错具体出在哪一行,无法更正是哪一行报出的异常,是否有好的解决方法。
------解决方法--------------------------------------------------------
1、用PL/SQL里面选择TEST->F9(开始测试)->打断点->选择执行到下一断点处。
2、使用DBMS_OUTPUT.PUT_LINE();每个SQL后面都加一个,结束后看看打印到那个就没了,对应的那个 SQL就是出问题的地方。
我通常写存储过程都用同一个EXCEPTION
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
P_ERR_LOG(SQLERRM,'PROCEDURE_NAME',SYSDATE);
ROLLBACK;
P_ERR_LOG是个存储过程,参数按顺序为:
错误信息、出错过程名称、时间
然后把信息存入一张日志表中。
------解决方法--------------------------------------------------------
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_CALL_STACK);
这样就能把错误的详细信息打印出来了
------解决方法--------------------------------------------------------
可以定义一个变量stmt_no,在每句前面为此变量赋值,如果出现exception,则stmt_no就是对应值的下一句,下面是Oracle给出的例子:
CREATE OR REPLACE PROCEDURE loc_var AS
stmt_no NUMBER;
name VARCHAR2(100);
BEGIN
stmt_no := 1; -- designates 1st SELECT statement
SELECT table_name INTO name
FROM user_tables
WHERE table_name LIKE 'ABC%';
stmt_no := 2; -- designates 2nd SELECT statement
SELECT table_name INTO name
FROM user_tables
WHERE table_name LIKE 'XYZ%';
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE
('Table name not found in query ' || stmt_no);
END;
/
CALL loc_var();
------解决方法--------------------------------------------------------
#4的做法是客户的1997版代码标准;
还有一种是尽量把逻辑写细到一个个小的procedure,然后用一个main procedure在包内调用,每次调用后将计数器加1,然后将该数字保存到一个专门的表中,知道最后一步成功后再将计数器置1,这样也容易知道错误位置,再次运行时可以从错误位置直接启动,restartbility非常好。这种写法是目前客户公司的2008版的代码标准。