在 Java 中调用 Oracle 存储过程时如何避免核心转储
Posted
技术标签:
【中文标题】在 Java 中调用 Oracle 存储过程时如何避免核心转储【英文标题】:How to avoid core dumps when calling Oracle stored procedure in Java 【发布时间】:2016-08-04 21:39:55 【问题描述】:我的 java 程序调用一个存储过程来解析文件并加载表中的属性。这是一个非常耗时的步骤,尤其是在进行软删除时(如果同一文件的新版本进来,我们不会更新旧记录,而是设置旧记录的删除标志)。 java 程序倾向于等到它完成。在某些情况下,当大量文件被加载到数据库时,java 程序会突然退出并生成核心转储。作为大型工作流程的一部分,退出此作业不会影响其余步骤。当它继续运行时,它将在下一步(也调用另一个存储过程)再次失败,并带有另一个核心转储和 hs_err_pid 日志文件。但是,加载文件的存储过程将继续运行,直到几个小时后完成。核心转储的时间戳表明它们正是 Oracle 执行软删除的时间。
通过阅读日志和核心转储,没有什么能告诉我出了什么问题。我使用 gdb 调试了核心转储,它只显示在调用过程期间发生的错误。我的猜测是 oracle 太忙于加载文件(软删除),并且在某些时候它反应迟钝,导致我的 JVM 崩溃,从而导致核心转储。出于类似的原因,这之后的工作也将在与 db 通信时出现问题,因为它仍然超载。
由于发生时 Oracle 端存在 SQL 异常,因此没有什么可捕获的。有没有办法避免像这样的致命错误以防止 JVM 崩溃?或者我如何告诉 Java 在调用存储过程后断开 db 而不是听 Oracle 并仅在过程完成时返回。
这是我用来调用该过程的java代码:
try
CallableStatement stmt = conn.prepareCall("call FILE_PROCESS.load_file(?,?,?,?,?,?,?,?,?)");
for (int i = 1; i < 10; i ++)
stmt.setString(i, arr[i - 1]);
stmt.registerOutParameter(7, Types.VARCHAR);
stmt.registerOutParameter(8, Types.VARCHAR);
stmt.registerOutParameter(9, Types.VARCHAR);
stmt.executeUpdate();
stmt.close();
conn.close();
catch (SQLException e)
e.printStackTrace();
System.exit(1);
编辑: 同时系统还生成了另一个文件“hs_err_pid26342.log”。我在下面粘贴了一些。它说明了一些关于 SR_Handler 的内容。这个方法是什么,怎么调用的?
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00002b95187851d3, pid=26342, tid=47919353368928
#
# JRE version: 7.0-b147
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0-b17 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x6f31d3] SR_handler(int, siginfo*, ucontext*)+0x43
【问题讨论】:
那个描述似乎没有意义。 Java 应用程序不会仅仅因为等待存储过程返回的时间过长而进行核心转储。在最坏的情况下,您会得到某种 SQL 超时异常,但这不会导致核心转储。如果您希望过程调用是异步的,您可以在数据库中提交一个运行存储过程的作业,将结果写入表,然后从应用程序轮询该表,但这并不明显会影响您的问题。跨度> @JustinCave 我不确定java是否等待太久。当数据库忙于执行软删除等操作时,它可能会失去与 Oracle 的通信。这可能没有意义,但在 java 端软删除和核心转储之间存在明显的相关性。 等待太久或失去通信不会导致核心转储。如果您编写一个简单地无限期等待并从 Java 调用它的存储过程,它将不会产生核心转储。 JVM 无法了解过程在运行时正在做什么,因此将核心转储与过程正在执行的特定操作相关联是没有意义的。这似乎更有可能是一种错误的关联,您需要再次查看核心转储,并让支持您的应用程序服务器的公司协助调试。 @JustinCave 我粘贴了一些 hs_err_pid 日志文件。看起来致命错误与SR_handler
有关。这是什么?
【参考方案1】:
一旦存储过程完成,我如何告诉 Java 断开 db 调用而不是听 Oracle 并且仅在过程时返回 完成。
查看 DBMS_SCHEDULER。
而不是Java运行
BEGIN
file_load_stored_proc;
END;
您可以将其编码到调度程序作业中,然后 java 会告诉数据库将该作业作为后台任务执行。数据库将在单独的数据库会话中启动作业,并立即将控制权交还给 Java 程序。
BEGIN
DBMS_SCHEDULER.RUN_JOB('FILE_LOAD_JOB',false);
END;
您可以将调度程序作业配置为在失败时发送电子邮件(如果您想要通知,甚至在成功时发送电子邮件)。
PS。我怀疑在数据库执行的某个地方发生了故障,而 Java 无法处理干净地提供核心转储的故障。调度程序作业应该可以更好地诊断那里的任何问题。
【讨论】:
以上是关于在 Java 中调用 Oracle 存储过程时如何避免核心转储的主要内容,如果未能解决你的问题,请参考以下文章
如何在java中调用包含用户定义类型的oracle存储过程?