SQLERRM 正在被覆盖
Posted
技术标签:
【中文标题】SQLERRM 正在被覆盖【英文标题】:SQLERRM is being overwritten 【发布时间】:2014-10-22 15:39:21 【问题描述】:我正在使用 SQLERRM。但是有更多的程序并行运行,所以有时 SQLERRM 会被其他程序覆盖。并行运行的意思是我同时运行过程 a 和过程 b。SQLERRM 是一个全局函数,这是我的问题。如果在两个过程中都抛出异常,则可能会发生,过程 a 修改过程 b 中的错误消息,过程 b 收到错误消息。 这些程序使用简单的构造:
BEGIN
--do something/cutted off
EXCEPTION
WHEN OTHERS THEN
write_log(SYSDATE, 'ERROR_1', SQLERRM);
END;
这些过程调用 write_log ,声明为
CREATE OR REPLACE PROCEDURE WRITE_LOG
(
TS_START IN DATE DEFAULT SYSDATE,
ERR_CODE IN VARCHAR DEFAULT NULL,
ERR_DESC IN VARCHAR DEFAULT NULL
)
IS
BEGIN
INSERT INTO LOG
( LOG_TS_START, LOG_ERR_CODE, LOG_ERR_DESC)
VALUES
(TS_START, ERR_CODE, ERR_DESC);
COMMIT;
END WRITE_LOG;
如何避免覆盖 SQLERRM ?正在写入日志,但错误消息是错误的。
【问题讨论】:
你的意思是write_log
处理的值不是你期望的吗? write_log
是如何定义的 - 它是直接引用 SQLERRM
本身还是过程参数? “并行运行”是指 write_log
是用 pragma autonomous_transaction
声明的吗?
欢迎来到PL/SQL
世界和常见错误。 EXCEPTION WHEN OTHERS
?一个真正的错误。
@LalitKumarB - 我真的希望这是对发布的简化,但我想不会再阅读它了。我认为这与实际问题无关。真的不清楚那是什么......
你可能是对的,但是错误堆栈永远不会与异常块相同。
为了完美调试,最好从各处移除接收块。
【参考方案1】:
首先,去掉PL/SQL
代码中的常见bug。
WHEN OTHERS THEN
没有RAISE
也没有任何合理的逻辑只是无用的,无非是一个错误。
删除所有exception blocks
,然后重试。并且,遵循良好的编码实践。
【讨论】:
+1 来自一个浪费了数周时间调试应用程序的人,这些应用程序静默失败,甚至不记录错误的行号。 100% 同意您的观点,但这并不能回答 OP 的问题。【参考方案2】:过程WRITE_LOG
没有使用传入的参数来执行INSERT
。试试看:
CREATE OR REPLACE PROCEDURE WRITE_LOG
(TS_START IN DATE DEFAULT SYSDATE,
ERR_CODE IN VARCHAR DEFAULT NULL,
ERR_DESC IN VARCHAR DEFAULT NULL)
IS
BEGIN
INSERT INTO LOG
(LOG_TS_START, LOG_ERR_CODE, LOG_ERR_DESC)
VALUES
(TS_START, ERR_CODE, ERR_DESC);
COMMIT;
END WRITE_LOG;
此外,在我看来,将错误记录到数据库表中是绝对错误的。因为您在日志记录过程中有一个COMMIT
语句,所以您将提交所有更改直到错误点,这很可能不是您想要做的。如果你愿意,你可以搞乱自主事务,但为了我的钱,最好的办法是登录到一个平面文件。
分享和享受。
【讨论】:
该函数使用参数,是一个错字(为了简化,我更改了一些名称)。编辑了查询。 当您发布代码时,请复制并粘贴真正使用的代码,而不是重新输入,这样可以消除此类问题。谢谢。【参考方案3】:写入日志表很常见,但使用自治事务进行日志记录是标准做法。这是因为您不希望主事务中的回滚影响日志记录,或者日志记录中的提交影响主事务。 (@BobJarvis 示例不是自治的)。
一个简单的例子显示在here。
日志表还有其他一些需要考虑的事情。一方面,您应该有一个使用 sys_guid(在表上定义)或触发器上的序列的 log_id。此外,使用 write_log 可用于区分正在写入日志消息的过程(或会话)的上下文字段。
添加此设置后(包括上下文),然后再次(同时)运行过程 a 和过程 b,并在上下文中传递过程名称(a 或 b)。您将能够在表格中看到 a 和 b 日志消息。
【讨论】:
以上是关于SQLERRM 正在被覆盖的主要内容,如果未能解决你的问题,请参考以下文章