【问题标题】:Stop a Java thread which calls an Oracle procedure停止调用 Oracle 过程的 Java 线程
【发布时间】:2010-08-04 20:05:50
【问题描述】:
在 Spring/Hibernate Web 应用程序中,我使用的是使用 Java 线程构建的工作队列。
Threads 的run() 方法调用一个Oracle 过程,该过程可以持续几分钟/几小时。工作队列的所有线程都存储在一个列表中。
我想构建一个界面 (JSP),我可以在其中显示正在运行的作业列表,并允许用户“杀死”一个作业。
我无法使用已弃用的 Thread.stop() 方法。我也已经用interrupt() 尝试了不同的方法,但是在Oracle 调用期间我没有成功停止线程。
- 您认为可以在 Oracle 调用期间停止线程吗?
- 否则,我是否应该寻找另一种方法来执行此工作队列(无线程)?
非常感谢!
【问题讨论】:
标签:
java
oracle
spring
multithreading
【解决方案1】:
“我应该寻找另一种方法吗
这个工作队列(没有线程)“
在我看来,您正在重新发明 Oracle 已经提供的数据库作业功能。
Oracle 10g 中引入了DBMS_SCHEDULER,相当复杂。在早期版本中,只有DBMS_JOB,这仍然相当不错:它在后台运行存储过程方面会比您当前的实现做得更好(ho ho)。
【解决方案2】:
您需要从 Web 应用程序调用 Statement.cancel(),如 indicated in this answer on SO。这可能不是一个很好的实现,因为对 Statement 对象的访问至少需要跨两个线程可用,这不一定是一个好的编程习惯。
编辑:
如果我不够清楚,您需要存储对正在执行查询的 Statement 对象的引用,如果用户选择取消作业的执行,则使它们可用于取消操作(将在不同的线程中执行) .如果这种方法失败(通常是由于对 Statement 对象的线程安全性假设不正确),您可以中断执行该语句的线程并从原始线程取消该语句的执行。
【解决方案3】:
问题是中断不会向 Oracle 的 JDBC 驱动程序发出信号来阻止。据我所知,使用已弃用的 Thread.stop() 杀死线程是您唯一的方法,除非您重新设计解决方案,甚至不能保证数据库中的操作实际停止。它可能仍在运行,除非您通过将语句暴露给 UI 控制逻辑来取消它,并且在终止线程后您将无法将 ROLLBACK 命令发送到数据库。
我的建议是让它运行,但向线程标记它应该在最终完成时执行 ROLLBACK。
另一个是让你的程序长时间不运行,并添加允许你干净地停止线程的中间步骤。
【解决方案4】:
这更像是对其他答案的备份。
您将遇到的大问题是,虽然可以终止 Java 线程,但 pl/sql 块可能会在服务器上继续执行一段时间。
我过去在 C 代码中遇到过这个问题,您的选择是尝试向服务器发送“取消”并等待其被确认(可能永远不会)或“尽力而为” , 无论如何都终止正在运行的线程,并在以后检测到客户端进程已离开时让 Oracle 清理。
APC 的回答很好 - 这听起来像是 Oracle 后台作业调度程序的理想案例,它提供了执行任务的良好视图,以及用于启动/停止/等的 API。
这里的一个小优势是您不会将 JDBC 连接池中的连接与长时间运行的事务捆绑在一起。
我认为在中间停止正在运行的任务可能仍然存在问题。 DBMS_JOB 的 Oracle 文档说,一旦作业开始,就无法停止。
我已经完成的一个解决方案是让我的后台作业定期检查“退出”条件(即表中是否存在一行) - 但只有在您有循环时才有效。